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 {
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_class_s *class;
void *data;
} 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_destructor) (void *data);
@ -107,17 +109,23 @@ typedef struct gib_classdesc_s {
struct gib_methodtab_s *methods, *class_methods;
} gib_classdesc_t;
#define GIB_Reply(mesg,argc,argv) if ((mesg).reply) ((mesg).reply(argc,argv,(mesg).replydata))
#define GIB_ForwardToSuper(mesg,obj,method) ((method)->parent->func ((obj), (method)->parent, (obj)->data[(method)->parent->class->depth], (mesg)))
#define GIB_Reply(obj,mesg,argc,argv) if ((mesg).reply) { \
((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);
gib_object_t *GIB_Object_Create (const char *classname, qboolean classobj);
void GIB_Object_Destroy (gib_object_t *obj);
void GIB_Object_Incref (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_SendToMethod (gib_object_t *obj, gib_method_t *method, 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, gib_object_t
*sender, int argc, const char **argv, gib_reply_handler reply,
void *replydata);
gib_object_t *GIB_Object_Get (const char *id);
void GIB_Object_Signal_Slot_Pair (gib_object_t *sender, const char *signal,
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);
// 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)
Hash_FlushTable (g->locals);
g->globals = gib_globals;
@ -110,6 +115,7 @@ GIB_Buffer_Reset (struct cbuf_s *cbuf)
g->program = g->ip = 0;
g->stack.p = 0;
g->waitret = false;
g->dnotify = NULL;
g->reply.obj = NULL;
}

View file

@ -321,10 +321,9 @@ GIB_Return_f (void)
for (i = 1; i < GIB_Argc(); 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);
g->dnotify = NULL;
GIB_Object_Decref (g->reply.obj);
} else if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp
&& GIB_DATA (sp)->waitret) {
int i;

View file

@ -57,87 +57,94 @@
*/
typedef struct baseobj_s {
llist_t *receivers, *subscribed;
unsigned long int ref;
} baseobj_t;
static int
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;
baseobj_t *base = data;
base->ref++;
GIB_Object_Incref (obj);
r = va ("%lu", obj->handle);
GIB_Reply (mesg, 1, &r);
GIB_Reply (obj, mesg, 1, &r);
return 0;
}
static int
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)
{
GIB_Object_Decref (obj);
baseobj_t *base = data;
if (base->ref) {
base->ref--;
GIB_Object_Decref (obj);
}
GIB_Reply (obj, mesg, 0, NULL);
return 0;
}
static int
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;
r = va ("%lu", obj->handle);
GIB_Reply (mesg, 1, &r);
GIB_Reply (obj, mesg, 1, &r);
return 0;
}
static int
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;
}
static int
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";
GIB_Object_Signal_Emit (obj, 1, &disposed);
GIB_Reply (mesg, 0, NULL);
GIB_Reply (obj, mesg, 0, NULL);
return 0;
}
static int
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;
if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2])))
GIB_Object_Signal_Slot_Pair (obj, mesg.argv[1], other,
mesg.argv[3]);
GIB_Reply (mesg, 0, NULL);
GIB_Reply (obj, mesg, 0, NULL);
return 0;
}
static int
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;
if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2])))
GIB_Object_Signal_Slot_Destroy (obj, mesg.argv[1], other,
mesg.argv[3]);
GIB_Reply (mesg, 0, NULL);
GIB_Reply (obj, mesg, 0, NULL);
return 0;
}
static int
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;
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);
old = mesg.argv[0];
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;
return 0;
}
@ -155,6 +163,8 @@ Object_Construct (gib_object_t *obj)
{
baseobj_t *base = malloc (sizeof (baseobj_t));
base->ref = 1;
return base;
}
@ -219,15 +229,14 @@ typedef struct Thread_s {
static int
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;
gib_function_t *f;
if (mesg.argc < 2 || !(f = GIB_Function_Find (mesg.argv[1]))) {
GIB_Reply (mesg, 0, NULL);
GIB_Object_Destroy (obj);
return 0;
return -1;
} else {
GIB_Function_Execute (t->thread, f, mesg.argv+1, mesg.argc-1);
Cbuf_Execute_Stack (t->thread);
@ -243,7 +252,7 @@ Thread_Cbuf_Freed (cbuf_t *cbuf, void *data)
t->thread = NULL;
t->ended = true;
GIB_Send (t->obj, 1, &release, NULL, NULL);
GIB_Send (t->obj, t->obj, 1, &release, NULL, NULL);
}
static void *
@ -335,15 +344,15 @@ Scrobj_Destruct (void *data)
static void
Scrobj_Thread_Died (cbuf_t *thread, void *data)
{
GIB_Reply (GIB_DATA(thread)->reply.mesg, 0, NULL);
GIB_Object_Decref (GIB_DATA(thread)->reply.obj);
GIB_Reply (GIB_DATA(thread)->reply.obj, GIB_DATA(thread)->reply.mesg, 0, NULL);
}
static int
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 send[] = "sender";
unsigned int ind;
cbuf_t *thread = GIB_Thread_New ();
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);
else
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);
return 0;

View file

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

View file

@ -179,7 +179,7 @@ GIB_Class_Create (gib_classdesc_t *desc)
// Create a class object
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)
{
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
@ -268,7 +268,8 @@ 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)
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_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.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
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;
@ -294,7 +301,11 @@ GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, int argc, const char
message.reply = reply;
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 *
@ -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))) {
for (cur = list; *cur; cur++) {
*argv = (*cur)->slot->mesg;
GIB_Send ((*cur)->receiver, argc, argv, NULL, NULL);
GIB_Send ((*cur)->receiver, sender, argc, argv, NULL, NULL);
}
free (list);
}