diff datum.c @ 0:76568becd6d6

Rhope Alpha 2a source import
author Mike Pavone <pavone@retrodev.com>
date Tue, 28 Apr 2009 23:06:07 +0000
parents
children 23dd9c766699
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datum.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,448 @@
+#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 SYLLABLE
+				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;
+}
+
+
+
+
+
+