mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
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:
parent
687a0845b6
commit
362d58fd95
6 changed files with 89 additions and 49 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue