cvsuser 04/02/07 04:58:59
Modified: include/parrot events.h interpreter.h
src events.c interpreter.c nci_test.c
t/pmc nci.t
Log:
approaching pdd16 callbacks
s. p6i for more
Revision Changes Path
1.11 +12 -2 parrot/include/parrot/events.h
Index: events.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/events.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -w -r1.10 -r1.11
--- events.h 17 Jan 2004 17:54:17 -0000 1.10
+++ events.h 7 Feb 2004 12:58:46 -0000 1.11
@@ -1,7 +1,7 @@
/* events.h
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
- * $Id: events.h,v 1.10 2004/01/17 17:54:17 leo Exp $
+ * $Id: events.h,v 1.11 2004/02/07 12:58:46 leo Exp $
* Overview:
* This api will handle parrot events
* Data Structure and Algorithms:
@@ -22,6 +22,7 @@
EVENT_TYPE_MSG,
EVENT_TYPE_ASYNC_IO,
EVENT_TYPE_TIMER,
+ EVENT_TYPE_CALL_BACK,
EVENT_TYPE_SLEEP,
EVENT_TYPE_TERMINATE,
EVENT_TYPE_EVENT_TERMINATE,
@@ -40,14 +41,21 @@
} parrot_timer_event;
typedef struct {
+ PMC* sub;
+ PMC* user_data;
+ void* external_data;
+} _call_back_info;
+
+typedef struct {
parrot_event_type_enum type;
Parrot_Interp interp;
- event_func_t event_func;
+ /* event_func_t event_func; unused */
void* data;
union {
STRING* msg; /* for testing only */
int signal; /* for EVENT_TYPE_SIGNAL */
parrot_timer_event timer_event; /* for EVENT_TYPE_TIMER */
+ _call_back_info call_back; /* CALL_BACKs */
} u;
} parrot_event;
@@ -70,6 +78,8 @@
void Parrot_new_terminate_event(Parrot_Interp);
void disable_event_checking(Parrot_Interp);
void enable_event_checking(Parrot_Interp);
+
+void Parrot_new_cb_event(Parrot_Interp, PMC*sub, PMC*user, void*ext);
void Parrot_kill_event_loop(void);
void* Parrot_sleep_on_event(Parrot_Interp, FLOATVAL t, void* next);
1.119 +6 -1 parrot/include/parrot/interpreter.h
Index: interpreter.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/interpreter.h,v
retrieving revision 1.118
retrieving revision 1.119
diff -u -w -r1.118 -r1.119
--- interpreter.h 4 Feb 2004 21:15:57 -0000 1.118
+++ interpreter.h 7 Feb 2004 12:58:46 -0000 1.119
@@ -1,7 +1,7 @@
/* interpreter.h
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
- * $Id: interpreter.h,v 1.118 2004/02/04 21:15:57 leo Exp $
+ * $Id: interpreter.h,v 1.119 2004/02/07 12:58:46 leo Exp $
* Overview:
* The interpreter api handles running the operations
* Data Structure and Algorithms:
@@ -334,6 +334,11 @@
void Parrot_runops_fromc(Parrot_Interp, PMC *sub);
void Parrot_runops_fromc_save(Parrot_Interp, PMC *sub);
void* Parrot_runops_fromc_args(Parrot_Interp, PMC *sub, const char *sig, ...);
+void* Parrot_runops_fromc_args_save(Parrot_Interp, PMC *, const char *, ...);
+
+void Parrot_callback_C(void *external_data, PMC *callback_info);
+void Parrot_callback_D(PMC *callback_info, void *external_data);
+PMC* Parrot_make_cb(Parrot_Interp interpreter, PMC* sub, PMC* user_data);
typedef opcode_t *(*native_func_t)(struct Parrot_Interp * interpreter,
opcode_t * cur_opcode,
1.29 +33 -1 parrot/src/events.c
Index: events.c
===================================================================
RCS file: /cvs/public/parrot/src/events.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -w -r1.28 -r1.29
--- events.c 30 Jan 2004 12:09:25 -0000 1.28
+++ events.c 7 Feb 2004 12:58:53 -0000 1.29
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: events.c,v 1.28 2004/01/30 12:09:25 leo Exp $
+$Id: events.c,v 1.29 2004/02/07 12:58:53 leo Exp $
=head1 NAME
@@ -301,6 +301,7 @@
entry->type = QUEUE_ENTRY_TYPE_TIMED_EVENT;
insert_entry(event_queue, entry);
break;
+ case EVENT_TYPE_CALL_BACK:
case EVENT_TYPE_SIGNAL:
entry->type = QUEUE_ENTRY_TYPE_EVENT;
unshift_entry(event_queue, entry);
@@ -366,6 +367,28 @@
/*
=item C<void
+Parrot_new_cb_event(Parrot_Interp, PMC*sub, PMC*user, void*ext)>
+
+Prepare and schedul a callback event
+
+=cut
+
+*/
+
+void
+Parrot_new_cb_event(Parrot_Interp interpreter, PMC* sub, PMC* user, void* ext)
+{
+ parrot_event* ev = mem_sys_allocate(sizeof(parrot_event));
+ ev->type = EVENT_TYPE_CALL_BACK;
+ ev->u.call_back.sub = sub;
+ ev->u.call_back.user_data = user;
+ ev->u.call_back.external_data = ext;
+ Parrot_schedule_event(interpreter, ev);
+}
+
+/*
+
+=item C<void
Parrot_del_timer_event(Parrot_Interp interpreter, PMC* timer)>
Deactivate the timer identified by C<timer>.
@@ -453,6 +476,7 @@
/*
* sleep checks events when it awakes
*/
+ edebug((stderr, "got entry - schedule_inter_qentry %d\n", event->type));
if (event->type != EVENT_TYPE_SLEEP)
enable_event_checking(interpreter);
/*
@@ -463,6 +487,7 @@
* in front or at the end of the queue
*/
switch (event->type) {
+ case EVENT_TYPE_CALL_BACK:
case EVENT_TYPE_SIGNAL:
unshift_entry(interpreter->task_queue, entry);
break;
@@ -1015,6 +1040,13 @@
/* run ops, save registers */
Parrot_runops_fromc_save(interpreter,
event->u.timer_event.sub);
+ break;
+ case EVENT_TYPE_CALL_BACK:
+ edebug((stderr, "starting user cb\n"));
+ Parrot_runops_fromc_args(interpreter, event->u.call_back.sub,
+ "PP",
+ event->u.call_back.user_data,
+ event->u.call_back.external_data);
break;
case EVENT_TYPE_SLEEP:
break;
1.262 +225 -8 parrot/src/interpreter.c
Index: interpreter.c
===================================================================
RCS file: /cvs/public/parrot/src/interpreter.c,v
retrieving revision 1.261
retrieving revision 1.262
diff -u -w -r1.261 -r1.262
--- interpreter.c 4 Feb 2004 21:16:07 -0000 1.261
+++ interpreter.c 7 Feb 2004 12:58:53 -0000 1.262
@@ -1,7 +1,7 @@
/*
################################################################################
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: interpreter.c,v 1.261 2004/02/04 21:16:07 leo Exp $
+$Id: interpreter.c,v 1.262 2004/02/07 12:58:53 leo Exp $
################################################################################
=head1 NAME
@@ -1011,9 +1011,13 @@
Parrot_runops_fromc_args(Parrot_Interp interpreter, PMC *sub,
const char *sig, ...)>
+=item C<void *
+Parrot_runops_fromc_args_save(Parrot_Interp interpreter, PMC *sub,
+ const char *sig, ...)>
+
Run parrot ops, called from C code, function arguments are passed as
C<va_args> according to signature the C<sub> argument is an invocable
-C<Sub> PMC.
+C<Sub> PMC. The latter preserves registers.
Signatures are similar to NCI:
@@ -1029,11 +1033,9 @@
*/
-void *
-Parrot_runops_fromc_args(Parrot_Interp interpreter, PMC *sub,
- const char *sig, ...)
+static void *
+runops_args(Parrot_Interp interpreter, PMC *sub, const char* sig, va_list ap)
{
- va_list ap;
/* *sig is retval like in NCI */
int ret;
int next[4];
@@ -1050,7 +1052,7 @@
REG_INT(4) = 0; /* # of N params */
ret = *sig++;
- va_start(ap, sig);
+
while (*sig) {
switch (*sig++) {
case 'v': /* void func, no params */
@@ -1077,7 +1079,6 @@
sig[-1]);
}
}
- va_end(ap);
Parrot_runops_fromc(interpreter, sub);
/*
@@ -1101,6 +1102,222 @@
ret);
}
return retval;
+}
+
+void *
+Parrot_runops_fromc_args(Parrot_Interp interpreter, PMC *sub,
+ const char *sig, ...)
+{
+ va_list args;
+ void *ret;
+
+ va_start(args, sig);
+ ret = runops_args(interpreter, sub, sig, args);
+ va_end(args);
+ return ret;
+}
+
+void *
+Parrot_runops_fromc_args_save(Parrot_Interp interpreter, PMC *sub,
+ const char *sig, ...)
+{
+ struct regsave *data = save_regs(interpreter);
+ va_list args;
+
+ va_start(args, sig);
+ (void) runops_args(interpreter, sub, sig, args);
+ va_end(args);
+ restore_regs(interpreter, data);
+ return NULL;
+}
+
+/*
+
+=item C<PMC* Parrot_make_cb(Parrot_Interp interpreter, PMC* sub, PMC* user)>
+
+Register a callback function according to pdd16
+
+=cut
+
+*/
+
+PMC*
+Parrot_make_cb(Parrot_Interp interpreter, PMC* sub, PMC* user_data)
+{
+ PMC* interp_pmc;
+ /*
+ * we stuff all the information into the Sub PMC and pass that
+ * on to the external sub
+ */
+ interp_pmc = VTABLE_get_pmc_keyed_int(interpreter, interpreter->iglobals,
+ (INTVAL) IGLOBALS_INTERPRETER);
+ VTABLE_setprop(interpreter, sub,
+ string_make(interpreter, "_interpreter", 12, NULL,
+ PObj_external_FLAG, NULL), interp_pmc);
+ VTABLE_setprop(interpreter, sub,
+ string_make(interpreter, "_user_data", 10, NULL,
+ PObj_external_FLAG, NULL), user_data);
+ /*
+ * we are gonna passing this PMC to external code, the PMCs
+ * might get out of scope until the callback is called -
+ * we don't know, when the callback will be called
+ *
+ * so anchor the PMC
+ */
+ dod_register_pmc(interpreter, sub);
+
+ /*
+ * finally the external lib awaits a function pointer
+ * fake a PMC that points to Parrot_callback_C (or _D)
+ */
+
+ return F2DPTR(Parrot_callback_C);
+}
+
+/*
+
+=item C<static void verify_CD(void *external_data, PMC *callback_info)>
+
+Verify callback_info PMC then continue with callback_CD
+
+=cut
+
+*/
+
+static void callback_CD(Parrot_Interp, void *, PMC *callback_info);
+
+static void
+verify_CD(void *external_data, PMC *callback_info)
+{
+ Parrot_Interp interpreter = NULL;
+ size_t i;
+
+ /*
+ * 1.) callback_info is from external code so:
+ * verify that we get a PMC that is one that we have passed in
+ * as user data, when we prepared the callback
+ */
+
+ /* a NULL pointer or a pointer not aligned is very likely wrong */
+ if (!callback_info || ((UINTVAL)callback_info & 3))
+ PANIC("callback_info doesn't look like a pointer");
+
+ /*
+ * we don't have an interpreter yet, where this PMC might be
+ * located so run through interpreters and check their PMC pools
+ */
+ LOCK(interpreter_array_mutex);
+ for (i = 0; i < n_interpreters; ++i) {
+ if (interpreter_array[i] == NULL)
+ continue;
+ interpreter = interpreter_array[i];
+ if (interpreter)
+ if (contained_in_pool(interpreter,
+ interpreter->arena_base->pmc_pool, callback_info))
+ break;
+ }
+ UNLOCK(interpreter_array_mutex);
+ if (!interpreter)
+ PANIC("interpreter not found for callback");
+
+ /*
+ * now we should have the interpreter where that callback
+ * did originate - do some further checks on the PMC
+ */
+
+ /* if that doesn't look like a PMC we are still lost */
+ if (!PObj_is_PMC_TEST(callback_info))
+ PANIC("callback_info isn't a PMC");
+
+ /*
+ * 2) some more checks: callback info is a Sub PMC
+ * we have passed a Sub PMC as user_data so check that
+ */
+ if (!callback_info->vtable)
+ PANIC("callback_info hasn't a vtable");
+ if (callback_info->vtable->base_type != enum_class_Sub)
+ PANIC("callback_info isn't a Sub PMC");
+ /*
+ * ok fine till here
+ */
+ callback_CD(interpreter, external_data, callback_info);
+}
+
+/*
+
+=item C<static void
+callback_CD(Parrot_Interp, void *external_data, PMC *callback_info)>
+
+Common callback function handler s. pdd16
+
+=cut
+
+*/
+
+static void
+callback_CD(Parrot_Interp interpreter, void *external_data, PMC *callback_info)
+{
+
+ PMC *passed_interp; /* the interp that originated the CB */
+ PMC *user_data; /* user really intended to get that back */
+ int async = 1; /* cb is hitting this sub somewhen inmidst */
+ /*
+ * 3) extract user_data, func signature, check interpreter ...
+ */
+ passed_interp = VTABLE_getprop(interpreter, callback_info,
+ string_from_cstring(interpreter, "_interpreter", 0));
+ if (PMC_data(passed_interp) != interpreter)
+ PANIC("callback gone to wrong interpreter");
+ user_data = VTABLE_getprop(interpreter, callback_info,
+ string_from_cstring(interpreter, "_user_data", 0));
+ /*
+ * 4) check if the call_back is synchronous:
+ * - if yes we are inside the NCI call
+ * we could run the Sub immediately now (I think)
+ * - if no, and that's always safe, post a CALLBACK_EVENT
+ */
+
+ if (async) {
+ /*
+ * create a CB_EVENT, put Sub and data inside and finito
+ *
+ * *if* this function is finally no void, i.e. the calling
+ * C program awaits a return result from the callback,
+ * then wait for the CB_EVENT_xx to finish and return the
+ * result
+ */
+ Parrot_new_cb_event(interpreter, callback_info,
+ user_data, external_data);
+ }
+ else {
+ /*
+ * just call the sub
+ */
+ }
+}
+
+/*
+
+=item C<void Parrot_callback_C(void *external_data, PMC *callback_info)>
+
+=item C<void Parrot_callback_D(PMC *callback_info, void *external_data)>
+
+NCI callback functions s. ppd16
+
+=cut
+
+*/
+
+void
+Parrot_callback_C(void *external_data, PMC *callback_info)
+{
+ verify_CD(external_data, callback_info);
+}
+
+void
+Parrot_callback_D(PMC *callback_info, void *external_data)
+{
+ verify_CD(external_data, callback_info);
}
/*
1.20 +14 -0 parrot/src/nci_test.c
Index: nci_test.c
===================================================================
RCS file: /cvs/public/parrot/src/nci_test.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -w -r1.19 -r1.20
--- nci_test.c 6 Feb 2004 10:57:37 -0000 1.19
+++ nci_test.c 7 Feb 2004 12:58:53 -0000 1.20
@@ -20,6 +20,9 @@
void * nci_pi(int test);
void nci_vP(void *pmc);
+typedef void (*cb_C1_func)(const char*, void*);
+void nci_cb_C1(cb_C1_func, void*);
+
double nci_dd(double d) {
return d * 2.0;
}
@@ -220,6 +223,17 @@
puts("ok");
else
puts("got null");
+}
+
+/*
+ * pdd16 tests
+ */
+void
+nci_cb_C1(cb_C1_func cb, void* user_data)
+{
+ const char *result = "succeded";
+ /* call the cb synchronously */
+ (cb)(result, user_data);
}
#ifdef TEST
1.28 +61 -1 parrot/t/pmc/nci.t
Index: nci.t
===================================================================
RCS file: /cvs/public/parrot/t/pmc/nci.t,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -w -r1.27 -r1.28
--- nci.t 6 Feb 2004 11:49:51 -0000 1.27
+++ nci.t 7 Feb 2004 12:58:59 -0000 1.28
@@ -1,4 +1,4 @@
-use Parrot::Test tests => 26;
+use Parrot::Test tests => 27;
use Parrot::Config;
print STDERR $PConfig{jitcpuarch}, " JIT CPU\n";
@@ -821,6 +821,66 @@
CODE
ok
got null
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "nci_cb_C1");
+ bounds 1 # no JIT yet
+ sweepoff # SEGV in dynext.c:235
+ # we need a flag if the call_back is already done
+ new P10, .PerlInt
+ store_global "cb_done", P10
+ # first attempt - create cb manually (this step will be hidden later)
+ newsub P5, .Sub, _call_back
+ null P1
+ dlfunc P0, P1, "Parrot_make_cb", "PIPP"
+ print "ok 1\n"
+ # prepare user data
+ new P6, .PerlInt
+ set P6, 42
+ # preserve the Sub
+ set P7, P5
+ # create callback (=> P5)
+ invoke
+ # now call the external sub, that takes a call_back and user_data
+ loadlib P1, "libnci"
+ dlfunc P0, P1, "nci_cb_C1", "vPP"
+ print "ok 2\n"
+ # P5 is the cb
+ # get user_data i.e. the Sub
+ set P6, P7
+ invoke
+ # call_back will be called at any time
+ # so spin a bit
+ set I20, 0
+loop:
+ inc I20
+ ## sleep 0.1 hangs sometimes in __select ## XXX ##
+ find_global P11, "cb_done"
+ if P11, fin
+ gt I20, 100000, err
+ branch loop
+fin:
+ print "done.\n"
+ end
+err:
+ print "cb didnt run\n"
+ end
+
+_call_back:
+ print "in callback\n"
+ print "user data: "
+ print P5
+ print "\n"
+ find_global P12, "cb_done"
+ inc P12
+ invoke P1
+
+CODE
+ok 1
+ok 2
+in callback
+user data: 42
+done.
OUTPUT
} # SKIP