~charles/libagar

42b64e5875351c2aa122c0f8e8e21c4e7f36ef15 — vedge 1 year, 2 months ago 1a039cf
Use a safe tailq traversal for FSEVENT/PROCEVENT-type EventSink callbacks.

This allows callbacks to use AG_DelEventSink() on the EventSink itself.

To help detect double-frees, trash the tag/name/cls in ObjectDestroy().

Add validity tests to AG_ObjectAttach() and AG_ObjectDetach().



git-svn-id: http://dev.csoft.net/agar/trunk@10423 86a84d31-9702-0410-8f1e-a60cab7bd424
4 files changed, 50 insertions(+), 18 deletions(-)

M ada/core/demo/agar_ada_core_demo.adb
M core/event.c
M core/object.c
M tools/agardb/agardb.cpp
M ada/core/demo/agar_ada_core_demo.adb => ada/core/demo/agar_ada_core_demo.adb +2 -3
@@ 108,8 108,7 @@ begin
 
  -- Objects can send events to each other.
  Post_Event
    (Source => My_Child_1,
     Target => My_Child_2,
    (Object => My_Child_2,
     Event  => "Ping");

  -- Propagate makes events broadcast to the object's descendants.


@@ 120,7 119,7 @@ begin
     Async     => False,
     Propagate => True);
  Post_Event
    (Target => My_Parent,
    (Object => My_Parent,
     Event  => "Ping");

  T_IO.Put_Line("My_Parent path = " & Get_Name(My_Parent));

M core/event.c => core/event.c +12 -6
@@ 1187,13 1187,17 @@ restart:
		case AG_SINK_READ:
		case AG_SINK_WRITE:
			es = (AG_EventSink *)kev->udata;
			es->fn(es, &es->fnArgs);
			if (es) {
				es->fn(es, &es->fnArgs);
			}
			break;
		case AG_SINK_FSEVENT:
		case AG_SINK_PROCEVENT:
			es = (AG_EventSink *)kev->udata;
			es->flagsMatched = GetSinkFlags(kev->fflags);
			es->fn(es, &es->fnArgs);
			if (es) {
				es->flagsMatched = GetSinkFlags(kev->fflags);
				es->fn(es, &es->fnArgs);
			}
			break;
		default:
			break;


@@ 1289,7 1293,7 @@ AG_EventSinkTIMERFD(void)
{
	fd_set rdFds, wrFds;
	int nFds, rv;
	AG_EventSink *es;
	AG_EventSink *es, *esNext;
	AG_Object *ob, *obNext;
	AG_Timer *to, *toNext;
	struct timeval timeo, *pTimeo;


@@ 1374,7 1378,10 @@ restart:
#  endif /* AG_TIMERS */
	
	/* 2. Process I/O events. */
	TAILQ_FOREACH(es, &agEventSource->sinks, sinks) {
	for (es = TAILQ_FIRST(&agEventSource->sinks);
	     es != TAILQ_END(&agEventSource->sinks);
	     es = esNext) {
		esNext = TAILQ_NEXT(es, sinks);
		switch (es->type) {
		case AG_SINK_READ:
			if (FD_ISSET(es->ident, &rdFds)) {


@@ 1388,7 1395,6 @@ restart:
			break;
		}
	}

	return (0);
}


M core/object.c => core/object.c +20 -7
@@ 350,6 350,10 @@ AG_ObjectAttach(void *parentp, void *pChld)
	if (parent == chld)
		AG_FatalErrorV("E31", "parent == chld");
#endif
#ifdef AG_TYPE_SAFETY
	if (!AG_OBJECT_VALID(parent)) { AG_FatalErrorV("E38a", "Parent object is invalid"); }
	if (!AG_OBJECT_VALID(chld))   { AG_FatalErrorV("E38b", "Child object is invalid"); }
#endif
	AG_LockVFS(parent);
	AG_ObjectLock(parent);
	AG_ObjectLock(chld);


@@ 415,7 419,10 @@ AG_ObjectDetach(void *pChld)
#ifdef AG_TIMERS
	AG_Timer *to, *toNext;
#endif

#ifdef AG_TYPE_SAFETY
	if (!AG_OBJECT_VALID(chld))   { AG_FatalErrorV("E36a", "Child object is invalid"); }
	if (!AG_OBJECT_VALID(parent)) { AG_FatalErrorV("E36b", "Parent object is invalid"); }
#endif
#ifdef AG_THREADS
	AG_LockVFS(root);
#endif


@@ 670,15 677,15 @@ AG_ObjectDestroy(void *p)
	AG_ObjectClass **hier;
	int i, nHier;

#ifdef AG_TYPE_SAFETY
	if (!AG_OBJECT_VALID(ob))
		AG_FatalErrorV("E36", "Object is invalid");
#endif
#ifdef AG_DEBUG
	if (ob->parent != NULL) {
		AG_Debug(ob, "I'm still attached to %s\n",
		    OBJECT(ob->parent)->name);
		AG_Debug(ob, "I'm still attached to %s\n", OBJECT(ob->parent)->name);
		AG_FatalErrorV("E33", "Object is still attached");
	}
# ifdef AG_DEBUG_CORE
	Debug(ob, "Destroying\n");
# endif
#endif
	AG_ObjectFreeChildren(ob);
	AG_ObjectReset(ob);


@@ 694,7 701,13 @@ AG_ObjectDestroy(void *p)
	AG_ObjectFreeVariables(ob);
	AG_ObjectFreeEvents(ob);
	AG_MutexDestroy(&ob->pvt.lock);

#ifdef AG_TYPE_SAFETY
	memcpy(ob->tag, "FreeMem", 7);
# ifdef AG_DEBUG
	memcpy(ob->name, "invalid", 7);
	ob->cls = NULL;
# endif
#endif
	if ((ob->flags & AG_OBJECT_STATIC) == 0)
		free(ob);
}

M tools/agardb/agardb.cpp => tools/agardb/agardb.cpp +16 -2
@@ 387,13 387,26 @@ PrintVersion(void)
/*
 * Debugger command entry
 */
static void *ExecCmdThread(void *);

static void
ExecCmd(AG_Event *event)
{
	AG_Textbox *tb = AG_TEXTBOX_SELF();
	char *s = AG_TextboxDupString(tb);
	AG_Thread th;

	AG_ThreadCreate(&th, ExecCmdThread, tb);
}
static void *
ExecCmdThread(void *arg)
{
	AG_Textbox *tb = AGTEXTBOX(arg);
	char *s;
	SBStream cmds;
	
	AG_OBJECT_ISA(tb, "AG_Widget:AG_Textbox:*");

	s = AG_TextboxDupString(tb);
	if (strcmp(s, "version") == 0)
		PrintVersion();



@@ 402,6 415,7 @@ ExecCmd(AG_Event *event)

	Agardb::Run_LLDB(cmds, 0);
	AG_TextboxClearString(tb);
	return (NULL);
}

static void


@@ 795,7 809,7 @@ Agardb::GUI::GUI()
		tb = g_textbox_prompt = AG_TextboxNew(box,
		    AG_TEXTBOX_EXCL | AG_TEXTBOX_HFILL,
		    "(lldb)");
		(AG_SetEvent(tb, "textbox-return", ExecCmd, NULL))->flags |= AG_EVENT_ASYNC;
		AG_SetEvent(tb, "textbox-return", ExecCmd, NULL);
	
		AG_ActionFn(g_console, "Help", ConsoleHelp, NULL);
		AG_ActionOnKey(g_console, AG_KEY_F1, AG_KEYMOD_ANY, "Help");