view datum.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -0400
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;
}