You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
7.0 KiB
265 lines
7.0 KiB
/*
|
|
* vm.c
|
|
*
|
|
* Copyright (c) 2000 Artur Rataj
|
|
* Distributed under the terms of the GNU General Public License
|
|
*
|
|
*/
|
|
|
|
#include "vm.h"
|
|
|
|
#define ERROR_VALUE INT_MAX
|
|
|
|
int vm_init_pool( struct tvm_pool** pool,
|
|
int area_size,
|
|
int max_stack_size,
|
|
int max_threads_num ) {
|
|
int position;
|
|
|
|
( *pool ) = (struct tvm_pool*)malloc( sizeof(struct tvm_pool) );
|
|
( *pool )->area_size = area_size;
|
|
( *pool )->area = (int*)malloc( (*pool)->area_size*sizeof(int) );
|
|
( *pool )->processes = NULL;
|
|
( *pool )->max_stack_size = max_stack_size;
|
|
( *pool )->max_threads_num = max_threads_num;
|
|
vm_enable_reverse( *pool, 0 );
|
|
for( position = 0; position < (*pool)->area_size; ++position )
|
|
( *pool )->area[position] = VM_OP_STOP;
|
|
return 1;
|
|
}
|
|
|
|
void vm_done_pool( struct tvm_pool* pool ) {
|
|
struct tvm_process* curr_process;
|
|
free( pool->area );
|
|
curr_process = pool->processes;
|
|
while( curr_process ) {
|
|
struct tvm_process* tmp_process;
|
|
|
|
tmp_process = curr_process;
|
|
curr_process = curr_process->next;
|
|
free( tmp_process->stack );
|
|
free( tmp_process );
|
|
}
|
|
free( pool );
|
|
}
|
|
|
|
static int push( struct tvm_pool* pool,
|
|
struct tvm_process* process,
|
|
int value ) {
|
|
if( process->stack_top == pool->max_stack_size )
|
|
return ERROR_VALUE;
|
|
else
|
|
process->stack[process->stack_top++] = value;
|
|
return 1;
|
|
}
|
|
|
|
static int pop( struct tvm_pool* pool,
|
|
struct tvm_process* process ) {
|
|
if( process->stack_top == 0 )
|
|
return ERROR_VALUE;
|
|
else
|
|
{
|
|
return process->stack[--process->stack_top];
|
|
}
|
|
}
|
|
|
|
void vm_modify( struct tvm_pool* pool,
|
|
int position,
|
|
int op ) {
|
|
pool->area[position] = op;
|
|
}
|
|
|
|
void vm_exec( struct tvm_pool* pool,
|
|
int position,
|
|
int age,
|
|
int reverse ) {
|
|
struct tvm_process* new_process;
|
|
|
|
new_process = (struct tvm_process*)malloc( sizeof(struct tvm_process) );
|
|
new_process->position = position;
|
|
new_process->stack = (int*)malloc( pool->max_stack_size*sizeof(int) );
|
|
new_process->stack_top = 0;
|
|
new_process->age = age;
|
|
new_process->reverse = reverse;
|
|
new_process->next = pool->processes;
|
|
pool->processes = new_process;
|
|
}
|
|
|
|
void vm_enable_reverse( struct tvm_pool* pool,
|
|
const int enabled ) {
|
|
pool->reverse_enabled = enabled;
|
|
}
|
|
|
|
int vm_get_reverse( struct tvm_pool* pool ) {
|
|
if( pool->reverse_enabled )
|
|
return (int)( vm_random(&(pool->vm_random_data))*2.0/
|
|
( VM_RAND_MAX + 1.0 ) );
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void vm_iterate( struct tvm_pool* pool,
|
|
char* modified ) {
|
|
struct tvm_process* prev_process;
|
|
struct tvm_process* curr_process;
|
|
struct tvm_process* next_process;
|
|
int processes_num;
|
|
|
|
processes_num = 0;
|
|
prev_process = NULL;
|
|
curr_process = pool->processes;
|
|
while( curr_process ) {
|
|
int op;
|
|
int arg;
|
|
int arg_2;
|
|
int arg_3;
|
|
|
|
++curr_process->age;
|
|
next_process = curr_process->next;
|
|
op = pool->area[curr_process->position];
|
|
if( curr_process->reverse )
|
|
--curr_process->position;
|
|
else
|
|
++curr_process->position;
|
|
curr_process->position = ( curr_process->position + pool->area_size )%
|
|
pool->area_size;
|
|
switch( op ) {
|
|
case VM_OP_WAIT:
|
|
break;
|
|
|
|
case VM_OP_STOP:
|
|
if( !prev_process )
|
|
pool->processes = curr_process->next;
|
|
else
|
|
prev_process->next = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
curr_process = prev_process;
|
|
--processes_num;
|
|
break;
|
|
|
|
case VM_OP_EXEC:
|
|
if( (arg = pop( pool, curr_process )) == ERROR_VALUE ) {
|
|
if( !prev_process )
|
|
pool->processes = curr_process->next;
|
|
else
|
|
prev_process->next = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
curr_process = prev_process;
|
|
--processes_num;
|
|
} else {
|
|
arg = curr_process->position + arg;
|
|
if( arg < 0 )
|
|
arg += pool->area_size;
|
|
if( arg >= pool->area_size )
|
|
arg -= pool->area_size;
|
|
vm_exec( pool, arg, curr_process->age, vm_get_reverse(pool) );
|
|
}
|
|
break;
|
|
|
|
case VM_OP_COPY:
|
|
if( (arg = pop( pool, curr_process )) == ERROR_VALUE ) {
|
|
if( !prev_process )
|
|
pool->processes = curr_process->next;
|
|
else
|
|
prev_process->next = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
curr_process = prev_process;
|
|
--processes_num;
|
|
} else if( (arg_2 = pop( pool, curr_process )) == ERROR_VALUE ) {
|
|
if( !prev_process )
|
|
pool->processes = curr_process->next;
|
|
else
|
|
prev_process->next = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
curr_process = prev_process;
|
|
--processes_num;
|
|
} else if( 1 && (arg_3 = pop( pool, curr_process )) == ERROR_VALUE ) {
|
|
if( !prev_process )
|
|
pool->processes = curr_process->next;
|
|
else
|
|
prev_process->next = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
curr_process = prev_process;
|
|
--processes_num;
|
|
} else {
|
|
int count;
|
|
int direction;
|
|
|
|
arg = curr_process->position + arg;
|
|
if( arg < 0 )
|
|
arg += pool->area_size;
|
|
if( arg >= pool->area_size )
|
|
arg -= pool->area_size;
|
|
arg_2 = curr_process->position + arg_2;
|
|
if( arg_2 < 0 )
|
|
arg_2 += pool->area_size;
|
|
if( arg_2 >= pool->area_size )
|
|
arg_2 -= pool->area_size;
|
|
if( curr_process->reverse )
|
|
direction = -1;
|
|
else
|
|
direction = 1;
|
|
for( count = 0; count < arg_3; ++count ) {
|
|
int i, j;
|
|
int offset;
|
|
|
|
offset = count*direction + pool->area_size;
|
|
i = pool->area[( arg_2 + offset )%pool->area_size];
|
|
j = pool->area[( arg_2 + offset )%pool->area_size] = pool->area[( arg + offset )%pool->area_size];
|
|
if( modified && i != j )
|
|
modified[( arg_2 + offset )%pool->area_size] = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default: /* >= VM_OP_PUSH */
|
|
arg = op - VM_OP_PUSH;
|
|
if( push(pool, curr_process, arg) == ERROR_VALUE ) {
|
|
if( !prev_process )
|
|
pool->processes = curr_process->next;
|
|
else
|
|
prev_process->next = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
curr_process = prev_process;
|
|
--processes_num;
|
|
}
|
|
break;
|
|
}
|
|
prev_process = curr_process;
|
|
curr_process = next_process;
|
|
++processes_num;
|
|
}
|
|
while( processes_num > pool->max_threads_num ) {
|
|
int process_num;
|
|
int curr_process_num;
|
|
|
|
process_num = (int)( vm_random(&(pool->vm_random_data))*1.0*processes_num/
|
|
( VM_RAND_MAX + 1.0 ) );
|
|
/*
|
|
process_num = (int)( rand()*1.0*processes_num/
|
|
( RAND_MAX + 1.0 ) );
|
|
*/
|
|
curr_process_num = 0;
|
|
curr_process = pool->processes;
|
|
prev_process = NULL;
|
|
while( curr_process_num != process_num ) {
|
|
prev_process = curr_process;
|
|
curr_process = curr_process->next;
|
|
++curr_process_num;
|
|
}
|
|
if( prev_process )
|
|
prev_process->next = curr_process->next;
|
|
else
|
|
pool->processes = curr_process->next;
|
|
free( curr_process->stack );
|
|
free( curr_process );
|
|
--processes_num;
|
|
}
|
|
}
|