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"
  
  
  

Reply via email to