Made reference counting of objects more sane. If a message is sent by an

object, the sending object is included in the message.  This is available
in GIB-scripted methods as the local variable "sender", which will be 0
if the sender was not an object.
This commit is contained in:
Brian Koropoff 2003-09-11 08:51:44 +00:00
parent 687a0845b6
commit 362d58fd95
6 changed files with 89 additions and 49 deletions

View file

@ -73,13 +73,15 @@ typedef struct gib_message_s {
typedef struct gib_method_s { typedef struct gib_method_s {
const char *name; const char *name;
int (*func) (struct gib_object_s *obj, struct gib_method_s *method, void *data, gib_message_t message); int (*func) (struct gib_object_s *obj, struct gib_method_s *method,
void *data, gib_object_t *sender, gib_message_t message);
struct gib_method_s *parent; struct gib_method_s *parent;
struct gib_class_s *class; struct gib_class_s *class;
void *data; void *data;
} gib_method_t; } gib_method_t;
typedef int (*gib_message_handler) (gib_object_t *obj, gib_method_t *method, void *data, gib_message_t message); typedef int (*gib_message_handler) (gib_object_t *obj, gib_method_t *method,
void *data, gib_object_t *sender, gib_message_t message);
typedef void * (*gib_obj_constructor) (gib_object_t *obj); typedef void * (*gib_obj_constructor) (gib_object_t *obj);
typedef void (*gib_obj_destructor) (void *data); typedef void (*gib_obj_destructor) (void *data);
@ -107,17 +109,23 @@ typedef struct gib_classdesc_s {
struct gib_methodtab_s *methods, *class_methods; struct gib_methodtab_s *methods, *class_methods;
} gib_classdesc_t; } gib_classdesc_t;
#define GIB_Reply(mesg,argc,argv) if ((mesg).reply) ((mesg).reply(argc,argv,(mesg).replydata)) #define GIB_Reply(obj,mesg,argc,argv) if ((mesg).reply) { \
#define GIB_ForwardToSuper(mesg,obj,method) ((method)->parent->func ((obj), (method)->parent, (obj)->data[(method)->parent->class->depth], (mesg))) ((mesg).reply(argc,argv,(mesg).replydata)); \
GIB_Object_Decref ((obj));}
#define GIB_ForwardToSuper(mesg,obj,method) ((method)->parent->func ((obj), \
(method)->parent, \
(obj)->data[(method)->parent->class->depth], \
(obj), (mesg)))
void GIB_Class_Create (gib_classdesc_t *desc); void GIB_Class_Create (gib_classdesc_t *desc);
gib_object_t *GIB_Object_Create (const char *classname, qboolean classobj); gib_object_t *GIB_Object_Create (const char *classname, qboolean classobj);
void GIB_Object_Destroy (gib_object_t *obj); void GIB_Object_Destroy (gib_object_t *obj);
void GIB_Object_Incref (gib_object_t *obj); void GIB_Object_Incref (gib_object_t *obj);
void GIB_Object_Decref (gib_object_t *obj); void GIB_Object_Decref (gib_object_t *obj);
int GIB_Send (gib_object_t *obj, int argc, const char **argv, gib_reply_handler reply, void *replydata); int GIB_Send (gib_object_t *obj, gib_object_t *sender, int argc, const char **argv, gib_reply_handler reply, void *replydata);
int GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, int argc, const int GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, gib_object_t
char **argv, gib_reply_handler reply, void *replydata); *sender, int argc, const char **argv, gib_reply_handler reply,
void *replydata);
gib_object_t *GIB_Object_Get (const char *id); gib_object_t *GIB_Object_Get (const char *id);
void GIB_Object_Signal_Slot_Pair (gib_object_t *sender, const char *signal, void GIB_Object_Signal_Slot_Pair (gib_object_t *sender, const char *signal,
gib_object_t *receiver, const char *slot); gib_object_t *receiver, const char *slot);

View file

@ -96,6 +96,11 @@ GIB_Buffer_Reset (struct cbuf_s *cbuf)
{ {
gib_buffer_data_t *g = GIB_DATA (cbuf); gib_buffer_data_t *g = GIB_DATA (cbuf);
// Being reset is nearly the same as being destroyed.
// It just means the buffer is going to be reused.
if (g->dnotify)
g->dnotify (cbuf, g->ddata);
if (g->locals) if (g->locals)
Hash_FlushTable (g->locals); Hash_FlushTable (g->locals);
g->globals = gib_globals; g->globals = gib_globals;
@ -110,6 +115,7 @@ GIB_Buffer_Reset (struct cbuf_s *cbuf)
g->program = g->ip = 0; g->program = g->ip = 0;
g->stack.p = 0; g->stack.p = 0;
g->waitret = false; g->waitret = false;
g->dnotify = NULL;
g->reply.obj = NULL; g->reply.obj = NULL;
} }

View file

@ -321,10 +321,9 @@ GIB_Return_f (void)
for (i = 1; i < GIB_Argc(); i++) for (i = 1; i < GIB_Argc(); i++)
argv[i-1] = GIB_Argv(i); argv[i-1] = GIB_Argv(i);
GIB_Reply (g->reply.mesg, GIB_Argc()-1, argv); GIB_Reply (g->reply.obj, g->reply.mesg, GIB_Argc()-1, argv);
free (argv); free (argv);
g->dnotify = NULL; g->dnotify = NULL;
GIB_Object_Decref (g->reply.obj);
} else if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp } else if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp
&& GIB_DATA (sp)->waitret) { && GIB_DATA (sp)->waitret) {
int i; int i;

View file

@ -57,87 +57,94 @@
*/ */
typedef struct baseobj_s { typedef struct baseobj_s {
llist_t *receivers, *subscribed; unsigned long int ref;
} baseobj_t; } baseobj_t;
static int static int
Object_Retain_f (gib_object_t *obj, gib_method_t *method, void *data, Object_Retain_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
const char *r; const char *r;
baseobj_t *base = data;
base->ref++;
GIB_Object_Incref (obj); GIB_Object_Incref (obj);
r = va ("%lu", obj->handle); r = va ("%lu", obj->handle);
GIB_Reply (mesg, 1, &r); GIB_Reply (obj, mesg, 1, &r);
return 0; return 0;
} }
static int static int
Object_Release_f (gib_object_t *obj, gib_method_t *method, void *data, Object_Release_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
baseobj_t *base = data;
if (base->ref) {
base->ref--;
GIB_Object_Decref (obj); GIB_Object_Decref (obj);
}
GIB_Reply (obj, mesg, 0, NULL);
return 0; return 0;
} }
static int static int
Object_Init_f (gib_object_t *obj, gib_method_t *method, void *data, Object_Init_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
const char *r; const char *r;
r = va ("%lu", obj->handle); r = va ("%lu", obj->handle);
GIB_Reply (mesg, 1, &r); GIB_Reply (obj, mesg, 1, &r);
return 0; return 0;
} }
static int static int
Object_Class_f (gib_object_t *obj, gib_method_t *method, void *data, Object_Class_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
GIB_Reply (mesg, 1, &obj->class->name); GIB_Reply (obj, mesg, 1, &obj->class->name);
return 0; return 0;
} }
static int static int
Object_Dispose_f (gib_object_t *obj, gib_method_t *method, void *data, Object_Dispose_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
static const char *disposed = "disposed"; static const char *disposed = "disposed";
GIB_Object_Signal_Emit (obj, 1, &disposed); GIB_Object_Signal_Emit (obj, 1, &disposed);
GIB_Reply (mesg, 0, NULL); GIB_Reply (obj, mesg, 0, NULL);
return 0; return 0;
} }
static int static int
Object_SignalConnect_f (gib_object_t *obj, gib_method_t *method, void *data, Object_SignalConnect_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
gib_object_t *other; gib_object_t *other;
if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2]))) if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2])))
GIB_Object_Signal_Slot_Pair (obj, mesg.argv[1], other, GIB_Object_Signal_Slot_Pair (obj, mesg.argv[1], other,
mesg.argv[3]); mesg.argv[3]);
GIB_Reply (mesg, 0, NULL); GIB_Reply (obj, mesg, 0, NULL);
return 0; return 0;
} }
static int static int
Object_SignalDisconnect_f (gib_object_t *obj, gib_method_t *method, void Object_SignalDisconnect_f (gib_object_t *obj, gib_method_t *method, void
*data, gib_message_t mesg) *data, gib_object_t *sender, gib_message_t mesg)
{ {
gib_object_t *other; gib_object_t *other;
if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2]))) if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2])))
GIB_Object_Signal_Slot_Destroy (obj, mesg.argv[1], other, GIB_Object_Signal_Slot_Destroy (obj, mesg.argv[1], other,
mesg.argv[3]); mesg.argv[3]);
GIB_Reply (mesg, 0, NULL); GIB_Reply (obj, mesg, 0, NULL);
return 0; return 0;
} }
static int static int
Object_Class_New_f (gib_object_t *obj, gib_method_t *method, void *data, Object_Class_New_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
const char *old; const char *old;
gib_object_t *new; gib_object_t *new;
@ -145,7 +152,8 @@ Object_Class_New_f (gib_object_t *obj, gib_method_t *method, void *data,
new = GIB_Object_Create (obj->class->name, false); new = GIB_Object_Create (obj->class->name, false);
old = mesg.argv[0]; old = mesg.argv[0];
mesg.argv[0] = "init"; mesg.argv[0] = "init";
GIB_Send (new, mesg.argc, mesg.argv, mesg.reply, mesg.replydata); GIB_Send (new, sender, mesg.argc, mesg.argv, mesg.reply, mesg.replydata);
GIB_Object_Decref (obj);
mesg.argv[0] = old; mesg.argv[0] = old;
return 0; return 0;
} }
@ -155,6 +163,8 @@ Object_Construct (gib_object_t *obj)
{ {
baseobj_t *base = malloc (sizeof (baseobj_t)); baseobj_t *base = malloc (sizeof (baseobj_t));
base->ref = 1;
return base; return base;
} }
@ -219,15 +229,14 @@ typedef struct Thread_s {
static int static int
Thread_Init_f (gib_object_t *obj, gib_method_t *method, void *data, Thread_Init_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
Thread_t *t = (Thread_t *) data; Thread_t *t = (Thread_t *) data;
gib_function_t *f; gib_function_t *f;
if (mesg.argc < 2 || !(f = GIB_Function_Find (mesg.argv[1]))) { if (mesg.argc < 2 || !(f = GIB_Function_Find (mesg.argv[1]))) {
GIB_Reply (mesg, 0, NULL);
GIB_Object_Destroy (obj); GIB_Object_Destroy (obj);
return 0; return -1;
} else { } else {
GIB_Function_Execute (t->thread, f, mesg.argv+1, mesg.argc-1); GIB_Function_Execute (t->thread, f, mesg.argv+1, mesg.argc-1);
Cbuf_Execute_Stack (t->thread); Cbuf_Execute_Stack (t->thread);
@ -243,7 +252,7 @@ Thread_Cbuf_Freed (cbuf_t *cbuf, void *data)
t->thread = NULL; t->thread = NULL;
t->ended = true; t->ended = true;
GIB_Send (t->obj, 1, &release, NULL, NULL); GIB_Send (t->obj, t->obj, 1, &release, NULL, NULL);
} }
static void * static void *
@ -335,15 +344,15 @@ Scrobj_Destruct (void *data)
static void static void
Scrobj_Thread_Died (cbuf_t *thread, void *data) Scrobj_Thread_Died (cbuf_t *thread, void *data)
{ {
GIB_Reply (GIB_DATA(thread)->reply.mesg, 0, NULL); GIB_Reply (GIB_DATA(thread)->reply.obj, GIB_DATA(thread)->reply.mesg, 0, NULL);
GIB_Object_Decref (GIB_DATA(thread)->reply.obj);
} }
static int static int
Scrobj_Method_f (gib_object_t *obj, gib_method_t *method, void *data, Scrobj_Method_f (gib_object_t *obj, gib_method_t *method, void *data,
gib_message_t mesg) gib_object_t *sender, gib_message_t mesg)
{ {
static char this[] = "this"; static char this[] = "this";
static char send[] = "sender";
unsigned int ind; unsigned int ind;
cbuf_t *thread = GIB_Thread_New (); cbuf_t *thread = GIB_Thread_New ();
static hashtab_t *nhash = NULL; static hashtab_t *nhash = NULL;
@ -363,7 +372,12 @@ Scrobj_Method_f (gib_object_t *obj, gib_method_t *method, void *data,
dsprintf (var->array[0].value, "%lu", obj->handle); dsprintf (var->array[0].value, "%lu", obj->handle);
else else
dstring_copystr (var->array[0].value, obj->class->name); dstring_copystr (var->array[0].value, obj->class->name);
GIB_Object_Incref (obj); var = GIB_Var_Get_Complex (&GIB_DATA(thread)->locals, &nhash, send,
&ind, true);
if (sender)
dsprintf (var->array[0].value, "%lu", sender->handle);
else
dstring_copystr (var->array[0].value, "0");
Cbuf_Execute_Stack (thread); Cbuf_Execute_Stack (thread);
return 0; return 0;

View file

@ -162,10 +162,11 @@ GIB_Execute_Prepare_Line (cbuf_t * cbuf, gib_tree_t * line)
if (cur->flags & TREE_A_EMBED) { if (cur->flags & TREE_A_EMBED) {
Cbuf_ArgsAdd (args, ""); Cbuf_ArgsAdd (args, "");
GIB_Process_Embedded (cur, cbuf->args); GIB_Process_Embedded (cur, cbuf->args);
} else } else {
Cbuf_ArgsAdd (args, cur->str); Cbuf_ArgsAdd (args, cur->str);
args->argm[args->argc - 1] = cur; args->argm[args->argc - 1] = cur;
} }
}
if (cur->delim == '(' if (cur->delim == '('
&& GIB_Process_Math (args->argv[args->argc - 1], pos)) && GIB_Process_Math (args->argv[args->argc - 1], pos))
return -1; return -1;
@ -296,20 +297,21 @@ GIB_Execute (cbuf_t * cbuf)
cbuf->state = CBUF_STATE_BLOCKED; cbuf->state = CBUF_STATE_BLOCKED;
i = super ? GIB_SendToMethod (obj, i = super ? GIB_SendToMethod (obj,
g->reply.method->parent, g->reply.method->parent,
i - 2, mesg, g->reply.obj, i - 2, mesg,
GIB_Buffer_Reply_Callback, GIB_Buffer_Reply_Callback,
cbuf) : GIB_Send (obj, cbuf) : GIB_Send (obj,
i - 2, mesg, g->reply.obj, i - 2, mesg,
GIB_Buffer_Reply_Callback, GIB_Buffer_Reply_Callback,
cbuf); cbuf);
} else { } else {
g->waitret = false; g->waitret = false;
i = super ? GIB_SendToMethod (obj, i = super ? GIB_SendToMethod (obj,
g->reply.method->parent, g->reply.method->parent,
i - 2, mesg, g->reply.obj, i - 2, mesg,
NULL, NULL) : NULL, NULL) :
GIB_Send (obj, i - 2, GIB_Send (obj,g->reply.obj,
mesg, NULL, NULL); i - 2, mesg, NULL,
NULL);
} }
if (i < 0) { if (i < 0) {
GIB_Error ( GIB_Error (

View file

@ -179,7 +179,7 @@ GIB_Class_Create (gib_classdesc_t *desc)
// Create a class object // Create a class object
class->classobj = GIB_Object_Create (desc->name, true); class->classobj = GIB_Object_Create (desc->name, true);
GIB_Send (class->classobj, 1, &init, NULL, NULL); GIB_Send (class->classobj, NULL, 1, &init, NULL, NULL);
} }
/* /*
@ -250,7 +250,7 @@ void
GIB_Object_Destroy (gib_object_t *obj) GIB_Object_Destroy (gib_object_t *obj)
{ {
const static char *dispose = "dispose"; const static char *dispose = "dispose";
GIB_Send (obj, 1, &dispose, GIB_Object_Finish_Destroy, obj); GIB_Send (obj, NULL, 1, &dispose, GIB_Object_Finish_Destroy, obj);
} }
void void
@ -268,7 +268,8 @@ GIB_Object_Decref (gib_object_t *obj)
} }
int int
GIB_Send (gib_object_t *obj, int argc, const char **argv, gib_reply_handler reply, void *replydata) GIB_Send (gib_object_t *obj, gib_object_t *sender, int argc, const char
**argv, gib_reply_handler reply, void *replydata)
{ {
gib_message_t message; gib_message_t message;
gib_method_t *method; gib_method_t *method;
@ -281,11 +282,17 @@ GIB_Send (gib_object_t *obj, int argc, const char **argv, gib_reply_handler repl
message.reply = reply; message.reply = reply;
message.replydata = replydata; message.replydata = replydata;
return method->func (obj, method, obj->data[method->class->depth], message); if (reply)
GIB_Object_Incref (obj);
return method->func (obj, method, obj->data[method->class->depth],
sender, message);
} }
int int
GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, int argc, const char **argv, gib_reply_handler reply, void *replydata) GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, gib_object_t
*sender, int argc, const char **argv, gib_reply_handler reply,
void *replydata)
{ {
gib_message_t message; gib_message_t message;
@ -294,7 +301,11 @@ GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, int argc, const char
message.reply = reply; message.reply = reply;
message.replydata = replydata; message.replydata = replydata;
return method->func (obj, method, obj->data[method->class->depth], message); if (reply)
GIB_Object_Incref (obj);
return method->func (obj, method, obj->data[method->class->depth],
sender, message);
} }
gib_object_t * gib_object_t *
@ -358,7 +369,7 @@ GIB_Object_Signal_Emit (gib_object_t *sender, int argc, const char **argv)
if ((list = (gib_signal_t **) Hash_FindList (sender->signals, *argv))) { if ((list = (gib_signal_t **) Hash_FindList (sender->signals, *argv))) {
for (cur = list; *cur; cur++) { for (cur = list; *cur; cur++) {
*argv = (*cur)->slot->mesg; *argv = (*cur)->slot->mesg;
GIB_Send ((*cur)->receiver, argc, argv, NULL, NULL); GIB_Send ((*cur)->receiver, sender, argc, argv, NULL, NULL);
} }
free (list); free (list);
} }