view datum.c @ 174:0c7c5671fcd3

Start work on interpreter
author Mike Pavone <pavone@retrodev.com>
date Thu, 19 May 2011 23:30:07 -0700
parents 23dd9c766699
children
line wrap: on
line source

#include "structs.h"
#include "datum.h"
#include "interp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
	#include <winsock.h>
#else
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netdb.h>
	#include <arpa/inet.h>
#endif

#ifdef TEXT_FILE_DEBUG
extern FILE * debugfile;
#endif

extern char * debugbuffer;

datum_storage first_datum_storage;
datum_storage * first_free;

VIS_CRITICAL_SECTION(datum_alloc_lock)

void init_datum_storage()
{
	short i;
	first_datum_storage.available = DATUMS_PER_STORAGE;
	for(i = 0; i < DATUMS_PER_STORAGE/8; ++i)
		first_datum_storage.inuse[i] = 0;
	first_datum_storage.next = NULL;
	//first_datum_storage.num = 0;
	//first_free = &first_datum_storage;
	VIS_InitializeCriticalSection(datum_alloc_lock);
}

datum * datum_alloc()
{
	short i, j;
	datum_storage *last, *current = /*first_free;*/&first_datum_storage;
	VIS_PROFILE_START(PROF_DATUM_ALLOC);
	//DEBUGPUTS("Begin datum_alloc()\n");
	VIS_EnterCriticalSection(datum_alloc_lock);
		while(current && !(current->available))
		{
			last = current;
			current = current->next;
		}
		if(current)
		{
			for(i = 0; i < (DATUMS_PER_STORAGE >> 3); ++i)
				if(current->inuse[i] != 0xFF)
					break;
			for(j = 0; j < 8; ++j)
				if(!CHECK_INUSE(current, i, j))
					break;
			//DEBUGPRINTF("inuse[%d] = %X\n", i, current->inuse[i]);
			i = (i << 3) | j;
			//DEBUGPRINTF("Allocated datum %X:%d\n", current, i);
			SET_INUSE(current, i);
			--(current->available);
	VIS_LeaveCriticalSection(datum_alloc_lock);
			//DEBUGPUTS("End datum_alloc()\n");
			//DEBUGPRINTF("datum_alloc(%X)\n", current->datums + i);
			VIS_PROFILE_END(PROF_DATUM_ALLOC);
			return current->datums + i;
		}
		else
		{
			current = MALLOC(sizeof(datum_storage),"datum storage");
			//first_free = current;
			//DEBUGPRINTF("New datum_storage %X\n", current);
			last->next = current;
			current->available = DATUMS_PER_STORAGE - 1;
			current->inuse[0] = 1;
			//current->num = last->num+1;
			for(i = 1; i < DATUMS_PER_STORAGE>>3; ++i)
				current->inuse[i] = 0;
			current->next = NULL;
	VIS_LeaveCriticalSection(datum_alloc_lock);
			//DEBUGPUTS("End datum_alloc()\n");
			//DEBUGPRINTF("datum_alloc(%X)\n", current->datums);
			VIS_PROFILE_END(PROF_DATUM_ALLOC);
			return current->datums;
		}
	
}

void free_datum(datum * adatum)
{
	datum_storage *last=NULL, *current = &first_datum_storage;
//	DEBUGPUTS("Begin free_datum()\n");
	VIS_EnterCriticalSection(datum_alloc_lock);
	while(current && !(adatum >= (datum *)current && adatum <= (((datum *)current) + DATUMS_PER_STORAGE)))
	{
		last = current;
		current = current->next;
	}
	if(current)
	{
		//DEBUGPRINTF("Freed datum %X:%d\n", current, adatum-((datum *)current));
		//DEBUGPRINTF("inuse[%d] = %X\n", (adatum-(current->datums))>>3, current->inuse[adatum-(current->datums)>>3]);
		//DEBUGPRINTF("&= %X\n", ~(1 << ((adatum-(current->datums)) & 3)));
		CLEAR_INUSE(current, adatum-(current->datums));
		//DEBUGPRINTF("inuse[%d] = %X\n", (adatum-(current->datums))>>3, current->inuse[adatum-(current->datums)>>3]);
		++(current->available);
		if(current->available == DATUMS_PER_STORAGE && last && last->available)
		{
			last->next = NULL;
			/*last->next = current->next;
			if(last->num < first_free->num || first_free == current)
				first_free = last;*/
			//DEBUGPRINTF("Freeing datum_storage %X\n", current);
			VIS_FREE(current, "free datum block");
		}
		/*else
		{
			if(current->num < first_free->num)
				first_free = current;
		}*/
	}
	VIS_LeaveCriticalSection(datum_alloc_lock);
	//DEBUGPUTS("End free_datum()\n");
}



datum * new_datum_comp(company * comp, unsigned char union_type, int generic_len)
{
	datum * adatum;
	VIS_PROFILE_START(PROF_NEW_DATUM);
	//adatum = datum_alloc();
	adatum = MALLOC(sizeof(datum),"datum");
	DEBUGPRINTF("Allocated: %X\n", adatum);
	//DEBUGPRINTF("datum_alloc returned %X.\n", adatum);
	adatum->company = comp;
	adatum->union_type = union_type;
	/*if(type > 0)
		adatum->methods = get_method_list(type);*/
	if(union_type == 1)//generic data
	{
		//DEBUGPUTS("union_type == 1\n");
		adatum->c.generic.len = generic_len;
		if(generic_len > 0)
		{
			//DEBUGPRINTF("malloc(%d);\n", generic_len);
			adatum->c.generic.data = MALLOC(generic_len,"datum generic data");
			//DEBUGPUTS("after malloc");
		}
		else
			adatum->c.generic.data = NULL;
	}
	adatum->ref_count = 1;
//	DEBUGPUTS("Initializing lock.\n");
	VIS_InitializeCriticalSection(adatum->lock);
	//DEBUGPRINTF( "New datum at: %X\n", adatum);
	VIS_PROFILE_END(PROF_NEW_DATUM);
	return adatum;
}

datum * new_datum(unsigned short type, unsigned char union_type, int generic_len, program * prog)
{
	return new_datum_comp(prog->companylist + type, union_type, generic_len);
}

datum * copy_datum(datum * adatum, int newsize)
{
	//NOTE: This function makes some assumptions that might not be safe everywhere in the interpretter, needs more thought
	int ref_count, real_len, new_entry_count;
	dict_data * dict;
	datum * output;
	worker_datum * work;
	int i;
	VIS_EnterCriticalSection(adatum->lock);
		ref_count = adatum->ref_count;
	VIS_LeaveCriticalSection(adatum->lock);
	if(adatum->union_type == 1)
		if(adatum->company->type_id == BUILTIN_TYPE_LIST)
			real_len = (adatum->c.generic.len-1) * sizeof(datum *) + sizeof(list_data);
		else
		{
			real_len = adatum->c.generic.len;
		}
	else
		real_len = 0;
	if(ref_count > 1 || newsize > real_len)
	{
		if(adatum->company->type_id == BUILTIN_TYPE_FILE)
		{
			VIS_EnterCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
				((file_data *)adatum->c.generic.data)->shared->ref_count++;
			VIS_LeaveCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
		}
		if(newsize)
			output = new_datum_comp(adatum->company, adatum->union_type, newsize);
		else
			output = new_datum_comp(adatum->company, adatum->union_type, real_len);
		switch(adatum->union_type)
		{
		case 1:
			if(adatum->company->type_id == BUILTIN_TYPE_LIST)
			{
				((list_data *)output->c.generic.data)->num_entries = ((list_data *)adatum->c.generic.data)->num_entries;
				for(i = 0; i < ((list_data *)adatum->c.generic.data)->num_entries; ++i)
					((list_data *)output->c.generic.data)->entries[i] = add_ref(((list_data *)adatum->c.generic.data)->entries[i]);
			}
		#ifdef GUI_LIB
			else if(adatum->company->type_id == BUILTIN_TYPE_WINDOW)
			{
				((vis_window *)output->c.generic.data)->title = add_ref(((vis_window *)adatum->c.generic.data)->title);
				((vis_window *)output->c.generic.data)->widget_dict = add_ref(((vis_window *)adatum->c.generic.data)->widget_dict);
				((vis_window *)output->c.generic.data)->widget_xpos = add_ref(((vis_window *)adatum->c.generic.data)->widget_xpos);
				((vis_window *)output->c.generic.data)->widget_ypos = add_ref(((vis_window *)adatum->c.generic.data)->widget_ypos);
				((vis_window *)output->c.generic.data)->id_list = add_ref(((vis_window *)adatum->c.generic.data)->id_list);
				((vis_window *)output->c.generic.data)->width = ((vis_window *)adatum->c.generic.data)->width;
				((vis_window *)output->c.generic.data)->height = ((vis_window *)adatum->c.generic.data)->height;
			}
		#ifdef SYLLABLE
			else if(adatum->company->type_id == BUILTIN_TYPE_BUTTON || adatum->company->type_id == BUILTIN_TYPE_INPUTBOX || adatum->company->type_id == BUILTIN_TYPE_CHECKBOX || adatum->company->type_id == BUILTIN_TYPE_DROPDOWN)
		#else
			else if(adatum->company->type_id == BUILTIN_TYPE_BUTTON || adatum->company->type_id == BUILTIN_TYPE_INPUTBOX)
		#endif
			{
				((vis_widget *)output->c.generic.data)->label = add_ref(((vis_widget *)adatum->c.generic.data)->label);
				((vis_widget *)output->c.generic.data)->value = add_ref(((vis_widget *)adatum->c.generic.data)->value);
				((vis_widget *)output->c.generic.data)->handler_dict = add_ref(((vis_widget *)adatum->c.generic.data)->handler_dict);
				((vis_widget *)output->c.generic.data)->width = ((vis_widget *)adatum->c.generic.data)->width;
				((vis_widget *)output->c.generic.data)->height = ((vis_widget *)adatum->c.generic.data)->height;
				((vis_widget *)output->c.generic.data)->flags = ((vis_widget *)adatum->c.generic.data)->flags;
			}
		#endif
			else if(real_len >= newsize && newsize)
				memcpy(output->c.generic.data, adatum->c.generic.data, newsize);
			else
				memcpy(output->c.generic.data, adatum->c.generic.data, real_len);
				
			if(adatum->company->build_size > 0)
			{
				for(i = 0; i < adatum->company->num_rooms; ++i)
						if(adatum->company->room_list[i].get_func_type == ROOM_VIS_REF)
						{
							//DEBUGPRINTF("Member add ref (get_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func), adatum->c.generic.data);
							add_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func)));
						}
						else if(adatum->company->room_list[i].set_func_type == ROOM_VIS_REF)
						{
							//DEBUGPRINTF("Member add ref (set_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func), adatum->c.generic.data);
							add_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func)));
						}
			}
			else if(adatum->company->type_id == BUILTIN_TYPE_DICT)
			{
				dict = output->c.generic.data;
				for(i = 0; i < dict->num_nodes; ++i)
						add_ref(dict->nodes[i].payload);
			}
			else if(adatum->company->type_id == BUILTIN_TYPE_WORKER)
			{
				work = output->c.generic.data;
				add_program_ref(work->def->program);
				for(i = 0; i < work->def->num_inputs; ++i)
					add_ref(work->params[i]);
			}
			
			if(adatum->c.generic.len != real_len)
				output->c.generic.len = adatum->c.generic.len;
			break;
		case 2:
			output->c.integers.num_a = adatum->c.integers.num_a;
			output->c.integers.num_b = adatum->c.integers.num_b;
			break;
		case 3:
			output->c.real = adatum->c.real;
			break;
		default:
			//oops;
			break;
		}
		release_ref(adatum);
	}
	else if(newsize && real_len == adatum->c.generic.len)
	{
		adatum->c.generic.len = newsize;
		output = adatum;
	}
	else
		output = adatum;
	return output;
}

datum * add_ref(datum * adatum)
{
	int tmp;
	VIS_PROFILE_START(PROF_ADDREF);
	if(!adatum)
	{
		//DEBUGPUTS("add_ref on NULL datum\n");
		return NULL;
	}
	DEBUGPRINTF("add_ref: %X\n",adatum);
	/*tmp = (int)(&(adatum->ref_count));
	__asm
	{
		mov ebx, tmp
		lock inc dword ptr [ebx]
	}*/
	
	VIS_EnterCriticalSection(adatum->lock);
		++(adatum->ref_count);
	VIS_LeaveCriticalSection(adatum->lock);
	VIS_PROFILE_END(PROF_ADDREF);
	return adatum;
}

void release_ref(datum * adatum)
{
	int i,tmp;
	dict_data * dict;
	worker_datum * worker;
	VIS_PROFILE_START(PROF_RELEASE);
	DEBUGPRINTF( "relase_ref: %X\n",adatum);
	if(!adatum)
		return;
	
	/*tmp = (int)(&(adatum->ref_count));
	__asm
	{
		mov ebx, tmp
		lock dec dword ptr [ebx]
	}*/
	//DEBUGPUTS("entering lock");
	VIS_EnterCriticalSection(adatum->lock);
		//DEBUGPUTS("got critical section\n");
		--(adatum->ref_count);
		if(adatum->ref_count == 0)
		{
			//DEBUGPRINTF("datum_free(%X)\n", adatum);
			
	VIS_LeaveCriticalSection(adatum->lock);
			//DEBUGPUTS("left lock");
			VIS_DeleteCriticalSection(adatum->lock);
			if(adatum->union_type == 1)
			{
				//DEBUGPRINTF( "Freeing adatum->c.generic.data(%X)\n",(int)adatum->c.generic.data);
				if(adatum->company->build_size > 0)
				{
					for(i = 0; i < adatum->company->num_rooms; ++i)
						if(adatum->company->room_list[i].get_func_type == ROOM_VIS_REF)
						{
							//DEBUGPRINTF("Member release ref (get_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func), adatum->c.generic.data);
							release_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func)));
						}
						else if(adatum->company->room_list[i].set_func_type == ROOM_VIS_REF)
						{
							//DEBUGPRINTF("Member release ref (set_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func), adatum->c.generic.data);
							release_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func)));
						}
				}
				else if(adatum->company->type_id == BUILTIN_TYPE_LIST)
					for(i = 0; i < ((list_data *)adatum->c.generic.data)->num_entries; ++i)
						release_ref(((list_data *)adatum->c.generic.data)->entries[i]);
				else if(adatum->company->type_id == BUILTIN_TYPE_FILE)
				{
					VIS_EnterCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
						--(((file_data *)adatum->c.generic.data)->shared->ref_count);
						if(((file_data *)adatum->c.generic.data)->shared->ref_count == 0)
						{
					VIS_LeaveCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
							VIS_DeleteCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
#ifndef SEGA
							if(((file_data *)adatum->c.generic.data)->shared->status == FILE_READ || ((file_data *)adatum->c.generic.data)->shared->status == FILE_WRITE)
								fclose(((file_data *)adatum->c.generic.data)->shared->file);
#endif
							VIS_FREE(((file_data *)adatum->c.generic.data)->shared, "Shared file struct");
						}
						else
						{
					VIS_LeaveCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
						}
				}
				else if(adatum->company->type_id == BUILTIN_TYPE_DICT)
				{
					dict = adatum->c.generic.data;
					for(i = 0; i < dict->num_nodes; ++i)
						release_ref(dict->nodes[i].payload);
				}
				else if(adatum->company->type_id == BUILTIN_TYPE_WORKER)
				{
					worker = adatum->c.generic.data;
					for(i = 0; i < worker->def->num_inputs; ++i)
						if(worker->params[i])
						{
							DEBUGPRINTF("Releasing worker param %d\n", i);
							release_ref(worker->params[i]);
						}
					release_program_ref(worker->def->program);
				}
				#ifdef GUI_LIB 
				else if(adatum->company->type_id == BUILTIN_TYPE_WINDOW)
				{
					release_ref(((vis_window *)adatum->c.generic.data)->title);
					release_ref(((vis_window *)adatum->c.generic.data)->widget_dict);
					release_ref(((vis_window *)adatum->c.generic.data)->widget_xpos);
					release_ref(((vis_window *)adatum->c.generic.data)->widget_ypos);
					release_ref(((vis_window *)adatum->c.generic.data)->id_list);
				}
				else if(adatum->company->type_id == BUILTIN_TYPE_BUTTON)
				{
					release_ref(((vis_widget *)adatum->c.generic.data)->label);
					release_ref(((vis_widget *)adatum->c.generic.data)->handler_dict);
				}
				#endif
				VIS_FREE(adatum->c.generic.data, "datum->c.generic.data");
			} else if(adatum->company->type_id == BUILTIN_TYPE_NETCLIENT)
			#ifdef WIN32
				closesocket(adatum->c.integers.num_a);
			#else
				close(adatum->c.integers.num_a);
			#endif
			else if(adatum->company->type_id == BUILTIN_TYPE_PROGRAM)
				release_program_ref(adatum->c.generic.data);
			DEBUGPRINTF("Freeing: %X\n",adatum);
			//free_datum(adatum);
			free(adatum);
		}
		else
		{
	VIS_LeaveCriticalSection(adatum->lock);
	//DEBUGPUTS("left lock");
		}
	VIS_PROFILE_END(PROF_RELEASE);
	//DEBUGPUTS("exit release_ref\n");
	
}

void datum_set_yesno(datum * adatum, int val)
{
	adatum->c.integers.num_a = val;
}