cvsuser 04/10/13 00:36:03
Modified: . libnci.def
src dynext.c inter_cb.c nci_test.c
t/pmc nci.t
Log:
[perl #31962] [PATCH] synchronous NCI callbacks
A callback sub is marked as 'sychchronous' by setting the property
'_synchronous' of the user_data to a true PMC. A neater solutin would be
automatic detection of safe synchronous execution. When the external library
calls the callback, then no callback event is put into the event queue, but
the sub is executed immediately.
A test is included in t/pmc/nci.t .
In src/nci.c the variable names 'user_data' and 'external_data' are now
consistently used.
Courtesy of Bernhard Schmalhofer <[EMAIL PROTECTED]>
Revision Changes Path
1.8 +6 -0 parrot/libnci.def
Index: libnci.def
===================================================================
RCS file: /cvs/public/parrot/libnci.def,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -w -r1.7 -r1.8
--- libnci.def 8 Oct 2004 11:57:38 -0000 1.7
+++ libnci.def 13 Oct 2004 07:35:59 -0000 1.8
@@ -19,8 +19,14 @@
nci_vP
nci_cb_C1
nci_cb_C2
+ nci_cb_C3
nci_cb_D1
+ nci_cb_D2
+ nci_cb_D3
+ nci_cb_D4
nci_pip
nci_i33
nci_vpii
nci_piiii
+ nci_dlvar_int
+ nci_dlvar_vv
1.35 +2 -2 parrot/src/dynext.c
Index: dynext.c
===================================================================
RCS file: /cvs/public/parrot/src/dynext.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -w -r1.34 -r1.35
--- dynext.c 8 Oct 2004 13:24:36 -0000 1.34
+++ dynext.c 13 Oct 2004 07:36:01 -0000 1.35
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: dynext.c,v 1.34 2004/10/08 13:24:36 leo Exp $
+$Id: dynext.c,v 1.35 2004/10/13 07:36:01 leo Exp $
=head1 NAME
@@ -217,7 +217,7 @@
}
err = Parrot_dlerror();
fprintf(stderr, "Couldn't load '%s': %s\n",
- full_name, err ? err : "unknown reason");
+ file_name, err ? err : "unknown reason");
return NULL;
}
1.3 +53 -41 parrot/src/inter_cb.c
Index: inter_cb.c
===================================================================
RCS file: /cvs/public/parrot/src/inter_cb.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -r1.2 -r1.3
--- inter_cb.c 16 Sep 2004 20:59:06 -0000 1.2
+++ inter_cb.c 13 Oct 2004 07:36:01 -0000 1.3
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: inter_cb.c,v 1.2 2004/09/16 20:59:06 jrieks Exp $
+$Id: inter_cb.c,v 1.3 2004/10/13 07:36:01 leo Exp $
=head1 NAME
@@ -8,9 +8,13 @@
=head1 DESCRIPTION
-NCI callback functions may run, whenever the C code executes the calback.
+NCI callback functions may run, whenever the C code executes the callback.
To be prepared for async callbacks these are converted to callback events.
+Often callbacks should run synchronously. This can only happen when
+the C-library calls the callback, because Parrot called a function in
+the C-library.
+
=head2 Functions
=over 4
@@ -105,31 +109,31 @@
/*
-=item C<static void verify_CD(void *external_data, PMC *callback_info)>
+=item C<static void verify_CD(void *external_data, PMC *user_data)>
-Verify callback_info PMC then continue with callback_CD
+Verify user_data PMC then continue with callback_CD
=cut
*/
-static void callback_CD(Parrot_Interp, void *, PMC *callback_info);
+static void callback_CD(Parrot_Interp, void *, PMC *user_data);
static void
-verify_CD(void *external_data, PMC *callback_info)
+verify_CD(void *external_data, PMC *user_data)
{
Parrot_Interp interpreter = NULL;
size_t i;
/*
- * 1.) callback_info is from external code so:
+ * 1.) user_data 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");
+ if (!user_data || ((UINTVAL)user_data & 3))
+ PANIC("user_data doesn't look like a pointer");
/*
* we don't have an interpreter yet, where this PMC might be
@@ -142,7 +146,7 @@
interpreter = interpreter_array[i];
if (interpreter)
if (contained_in_pool(interpreter,
- interpreter->arena_base->pmc_pool, callback_info))
+ interpreter->arena_base->pmc_pool, user_data))
break;
}
UNLOCK(interpreter_array_mutex);
@@ -156,21 +160,21 @@
*/
/* 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");
+ if (!PObj_is_PMC_TEST(user_data))
+ PANIC("user_data isn't a PMC");
- if (!callback_info->vtable)
- PANIC("callback_info hasn't a vtable");
+ if (!user_data->vtable)
+ PANIC("user_data hasn't a vtable");
/*
* ok fine till here
*/
- callback_CD(interpreter, external_data, callback_info);
+ callback_CD(interpreter, external_data, user_data);
}
/*
=item C<static void
-callback_CD(Parrot_Interp, void *external_data, PMC *callback_info)>
+callback_CD(Parrot_Interp, void *external_data, PMC *user_data)>
Common callback function handler s. pdd16
@@ -179,19 +183,26 @@
*/
static void
-callback_CD(Parrot_Interp interpreter, void *external_data, PMC *callback_info)
+callback_CD(Parrot_Interp interpreter, void *external_data, PMC *user_data)
{
PMC *passed_interp; /* the interp that originated the CB */
- int async = 1; /* cb is hitting this sub somewhen inmidst */
+ PMC *passed_synchronous; /* flagging synchronous execution */
+ int synchronous = 0; /* cb is hitting this sub somewhen inmidst, or not */
STRING *sc;
/*
* 3) check interpreter ...
*/
sc = CONST_STRING(interpreter, "_interpreter");
- passed_interp = VTABLE_getprop(interpreter, callback_info, sc);
+ passed_interp = VTABLE_getprop(interpreter, user_data, sc);
if (PMC_data(passed_interp) != interpreter)
PANIC("callback gone to wrong interpreter");
+
+ sc = CONST_STRING(interpreter, "_synchronous");
+ passed_synchronous = VTABLE_getprop(interpreter, user_data, sc);
+ if (passed_synchronous && VTABLE_get_bool(interpreter, passed_synchronous))
+ synchronous = 1;
+
/*
* 4) check if the call_back is synchronous:
* - if yes we are inside the NCI call
@@ -199,7 +210,13 @@
* - if no, and that's always safe, post a CALLBACK_EVENT
*/
- if (async) {
+ if ( synchronous ) {
+ /*
+ * just call the sub
+ */
+ Parrot_run_callback(interpreter, user_data, external_data);
+ }
+ else {
/*
* create a CB_EVENT, put user_data and data inside and finito
*
@@ -208,12 +225,7 @@
* then wait for the CB_EVENT_xx to finish and return the
* result
*/
- Parrot_new_cb_event(interpreter, callback_info, external_data);
- }
- else {
- /*
- * just call the sub
- */
+ Parrot_new_cb_event(interpreter, user_data, external_data);
}
}
@@ -221,7 +233,7 @@
=item C<void
-Parrot_run_callback(Parrot_Interp interpreter, PMC* user_data, void* ext)>
+Parrot_run_callback(Parrot_Interp interpreter, PMC* user_data, void* external_data)>
Run a callback function. The PMC* user_data holds all
necessary items in its properties.
@@ -231,7 +243,7 @@
*/
void
-Parrot_run_callback(Parrot_Interp interpreter, PMC* user_data, void* ext)
+Parrot_run_callback(Parrot_Interp interpreter, PMC* user_data, void* external_data)
{
PMC * signature;
PMC * sub;
@@ -265,16 +277,16 @@
case '4':
#endif
case 'l':
- i_param = (INTVAL)(long) ext;
+ i_param = (INTVAL)(long) external_data;
goto case_I;
case 'i':
- i_param = (INTVAL)(int)(long) ext;
+ i_param = (INTVAL)(int)(long) external_data;
goto case_I;
case 's':
- i_param = (INTVAL)(short)(long) ext;
+ i_param = (INTVAL)(short)(long) external_data;
goto case_I;
case 'c':
- i_param = (INTVAL)(char)(long)ext;
+ i_param = (INTVAL)(char)(long)external_data;
case_I:
pasm_sig[2] = 'I';
param = (void*) i_param;
@@ -290,7 +302,7 @@
case 'p':
/* created a UnManagedStruct */
p_param = pmc_new(interpreter, enum_class_UnManagedStruct);
- PMC_data(p_param) = ext;
+ PMC_data(p_param) = external_data;
pasm_sig[2] = 'P';
param = (void*) p_param;
break;
@@ -301,7 +313,7 @@
#endif
case 't':
pasm_sig[2] = 'S';
- param = string_from_cstring(interpreter, ext, 0);
+ param = string_from_cstring(interpreter, external_data, 0);
break;
default:
internal_exception(1, "unhandled signature char '%c' in run_cb", *p);
@@ -312,9 +324,9 @@
}
/*
-=item C<void Parrot_callback_C(void *external_data, PMC *callback_info)>
+=item C<void Parrot_callback_C(void *external_data, PMC *user_data)>
-=item C<void Parrot_callback_D(PMC *callback_info, void *external_data)>
+=item C<void Parrot_callback_D(PMC *user_data, void *external_data)>
NCI callback functions s. ppd16
@@ -323,15 +335,15 @@
*/
void
-Parrot_callback_C(void *external_data, PMC *callback_info)
+Parrot_callback_C(void *external_data, PMC *user_data)
{
- verify_CD(external_data, callback_info);
+ verify_CD(external_data, user_data);
}
void
-Parrot_callback_D(PMC *callback_info, void *external_data)
+Parrot_callback_D(PMC *user_data, void *external_data)
{
- verify_CD(external_data, callback_info);
+ verify_CD(external_data, user_data);
}
/*
1.35 +28 -1 parrot/src/nci_test.c
Index: nci_test.c
===================================================================
RCS file: /cvs/public/parrot/src/nci_test.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -w -r1.34 -r1.35
--- nci_test.c 8 Oct 2004 11:57:40 -0000 1.34
+++ nci_test.c 13 Oct 2004 07:36:01 -0000 1.35
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2004 The Perl Foundation. All Rights Reserved.
-$Id: nci_test.c,v 1.34 2004/10/08 11:57:40 leo Exp $
+$Id: nci_test.c,v 1.35 2004/10/13 07:36:01 leo Exp $
=head1 NAME
@@ -81,6 +81,9 @@
typedef void (*cb_D3_func)(void*, void*);
void nci_cb_D3(cb_D3_func, void*);
+typedef void (*cb_D4_func)(void*, void*);
+void nci_cb_D4(cb_D4_func, void*);
+
typedef struct {
int y;
} Nested;
@@ -376,12 +379,16 @@
const char *result = "succeeded";
/* call the cb synchronously */
(cb)(result, user_data);
+
+ return;
}
void
nci_cb_C2(cb_C2_func cb, void* user_data) {
/* call the cb synchronously */
(cb)(77, user_data);
+
+ return;
}
static int int_cb_C3 = 99;
@@ -389,6 +396,8 @@
nci_cb_C3(cb_C3_func cb, void* user_data) {
/* call the cb synchronously */
(cb)(&int_cb_C3, user_data);
+
+ return;
}
void
@@ -396,12 +405,16 @@
const char *result = "succeeded";
/* call the cb synchronously */
(cb)(user_data, result);
+
+ return;
}
void
nci_cb_D2(cb_D2_func cb, void* user_data) {
/* call the cb synchronously */
(cb)(user_data, 88);
+
+ return;
}
static int int_cb_D3 = 111;
@@ -409,8 +422,22 @@
nci_cb_D3(cb_D3_func cb, void* user_data) {
/* call the cb synchronously */
(cb)(user_data, &int_cb_D3);
+
+ return;
+}
+
+static int int_cb_D4 = 1;
+void
+nci_cb_D4(cb_D4_func times_ten, void* user_data) {
+ int cnt;
+ for ( cnt = 0; cnt < 10; cnt++ )
+ {
+ (times_ten)(user_data, &int_cb_D4);
+ int_cb_D4++;
}
+ return;
+}
void
nci_pip (int count, Rect_Like *rects) {
1.56 +72 -2 parrot/t/pmc/nci.t
Index: nci.t
===================================================================
RCS file: /cvs/public/parrot/t/pmc/nci.t,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -w -r1.55 -r1.56
--- nci.t 12 Oct 2004 09:00:26 -0000 1.55
+++ nci.t 13 Oct 2004 07:36:03 -0000 1.56
@@ -1,7 +1,7 @@
#! perl -w
# Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-# $Id: nci.t,v 1.55 2004/10/12 09:00:26 leo Exp $
+# $Id: nci.t,v 1.56 2004/10/13 07:36:03 leo Exp $
=head1 NAME
@@ -24,7 +24,7 @@
=cut
-use Parrot::Test tests => 46;
+use Parrot::Test tests => 47;
use Parrot::Config;
SKIP: {
@@ -1576,6 +1576,76 @@
OUTPUT
+output_is(<<'CODE', <<'OUTPUT', "nci_cb_D4 - synchronous callbacks");
+##PIR##
+
+.include "datatypes.pasm"
+
+.sub _test @MAIN
+
+ # prepare user data
+ .local pmc user_data
+ user_data = new Integer
+ user_data = 42
+
+ # A Sub that can be given to the library
+ # this callback function will eventually by called by the library
+ .local pmc cb
+ cb = newsub _call_back
+ .local pmc cb_wrapped
+ cb_wrapped = new_callback cb, user_data, "Up" # Z in pdd16
+ print "created a callback sub\n"
+ .local pmc synchronous
+ synchronous = new Integer
+ synchronous = 1
+ setprop user_data, "_synchronous", synchronous
+ print "marked callback as synchronous\n"
+
+ # now call the external sub, that takes a callback and user data
+ .local pmc libnci
+ libnci = loadlib "libnci"
+ .local pmc nci_cb_D4
+ nci_cb_D4 = dlfunc libnci, "nci_cb_D4", "vpP"
+ print "loaded a function that takes a callback\n"
+ nci_cb_D4( cb_wrapped, user_data )
+
+ end
+.end
+
+.sub _call_back
+ # P6 is a UnManagedStruct PMC containing a pointer to an integer
+ new P2, .PerlArray
+ push P2, .DATATYPE_INT
+ push P2, 0
+ push P2, 0
+ assign P6, P2
+
+ print "external data: "
+ I17 = P6[0]
+ print I17
+ print "\n"
+ I17 = I17 * 10
+ P6[0] = I17
+
+ invoke P1
+.end
+
+CODE
+created a callback sub
+marked callback as synchronous
+loaded a function that takes a callback
+external data: 1
+external data: 11
+external data: 111
+external data: 1111
+external data: 11111
+external data: 111111
+external data: 1111111
+external data: 11111111
+external data: 111111111
+external data: 1111111111
+OUTPUT
+
output_is(<<'CODE', <<'OUTPUT', 'nci_pip - array of structs');
.include "datatypes.pasm"