2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/interp/inter_cb.c - Parrot Interpreter - Callback Function Handling
11 NCI callback functions may run whenever the C code executes the callback.
12 To be prepared for asynchronous callbacks these are converted to callback
15 Often callbacks should run synchronously. This can only happen when
16 the C-library calls the callback, because Parrot called a function in
27 #include "parrot/parrot.h"
28 #include "parrot/extend.h"
29 #include "pmc/pmc_parrotinterpreter.h"
30 #include "inter_cb.str"
33 /* HEADERIZER HFILE: include/parrot/interpreter.h */
35 /* HEADERIZER BEGIN: static */
36 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
38 static void callback_CD(PARROT_INTERP
,
39 ARGIN(char *external_data
),
40 ARGMOD(PMC
*user_data
))
41 __attribute__nonnull__(1)
42 __attribute__nonnull__(2)
43 __attribute__nonnull__(3)
44 FUNC_MODIFIES(*user_data
);
46 static void verify_CD(
47 ARGIN(char *external_data
),
48 ARGMOD_NULLOK(PMC
*user_data
))
49 __attribute__nonnull__(1)
50 FUNC_MODIFIES(*user_data
);
52 #define ASSERT_ARGS_callback_CD __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
53 PARROT_ASSERT_ARG(interp) \
54 , PARROT_ASSERT_ARG(external_data) \
55 , PARROT_ASSERT_ARG(user_data))
56 #define ASSERT_ARGS_verify_CD __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
57 PARROT_ASSERT_ARG(external_data))
58 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
59 /* HEADERIZER END: static */
63 =item C<PMC* Parrot_make_cb(PARROT_INTERP, PMC* sub, PMC* user_data, STRING
66 Create a callback function according to pdd16.
73 PARROT_CANNOT_RETURN_NULL
74 PARROT_WARN_UNUSED_RESULT
76 Parrot_make_cb(PARROT_INTERP
, ARGMOD(PMC
* sub
), ARGIN(PMC
* user_data
),
77 ARGIN(STRING
*cb_signature
))
79 ASSERT_ARGS(Parrot_make_cb
)
83 char * const signature
= Parrot_str_to_cstring(interp
, cb_signature
);
85 * we stuff all the information into the user_data PMC and pass that
86 * on to the external sub
88 PMC
* const interp_pmc
= VTABLE_get_pmc_keyed_int(interp
, interp
->iglobals
,
89 (INTVAL
) IGLOBALS_INTERPRETER
);
91 /* be sure __LINE__ is consistent */
92 sc
= CONST_STRING(interp
, "_interpreter");
93 VTABLE_setprop(interp
, user_data
, sc
, interp_pmc
);
94 sc
= CONST_STRING(interp
, "_sub");
95 VTABLE_setprop(interp
, user_data
, sc
, sub
);
96 /* only ASCII signatures are supported */
97 if (strlen(signature
) == 3) {
98 /* Callback return type ignored */
100 if (signature
[1] == 'U') {
104 if (signature
[2] == 'U') {
109 Parrot_str_free_cstring(signature
);
110 if (type
!= 'C' && type
!= 'D')
111 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
112 "unhandled signature '%Ss' in make_cb", cb_signature
);
114 cb_sig
= Parrot_pmc_new(interp
, enum_class_String
);
115 VTABLE_set_string_native(interp
, cb_sig
, cb_signature
);
116 sc
= CONST_STRING(interp
, "_signature");
117 VTABLE_setprop(interp
, user_data
, sc
, cb_sig
);
119 * We are going to be passing the user_data PMC to external code, but
120 * it may go out of scope until the callback is called -- we don't know
121 * for certain as we don't know when the callback will be called.
122 * Therefore, to prevent the PMC from being destroyed by a GC sweep,
123 * we need to anchor it.
126 Parrot_pmc_gc_register(interp
, user_data
);
129 * Finally, the external lib awaits a function pointer.
130 * Create a PMC that points to Parrot_callback_C (or _D);
131 * it can be passed on with signature 'p'.
133 cb
= Parrot_pmc_new(interp
, enum_class_UnManagedStruct
);
135 * Currently, we handle only 2 types:
136 * _C ... user_data is 2nd parameter
137 * _D ... user_data is 1st parameter
140 VTABLE_set_pointer(interp
, cb
, F2DPTR(Parrot_callback_C
));
142 VTABLE_set_pointer(interp
, cb
, F2DPTR(Parrot_callback_D
));
143 Parrot_pmc_gc_register(interp
, cb
);
150 =item C<static void verify_CD(char *external_data, PMC *user_data)>
152 Verify user_data PMC then continue with callback_CD
159 verify_CD(ARGIN(char *external_data
), ARGMOD_NULLOK(PMC
*user_data
))
161 ASSERT_ARGS(verify_CD
)
162 PARROT_INTERP
= NULL
;
167 * 1.) user_data is from external code so:
168 * verify that we get a PMC that is one that we have passed in
169 * as user data, when we prepared the callback
172 /* a NULL pointer or a pointer not aligned is very likely wrong */
174 PANIC(interp
, "user_data is NULL");
175 if (PMC_IS_NULL(user_data
))
176 PANIC(interp
, "user_data is PMCNULL");
177 if ((UINTVAL
)user_data
& 3)
178 PANIC(interp
, "user_data doesn't look like a pointer");
180 /* Fetch original interpreter from prop */
181 LOCK(interpreter_array_mutex
);
183 interp
= interpreter_array
[0];
184 sc
= CONST_STRING(interp
, "_interpreter");
185 interp_pmc
= VTABLE_getprop(interp
, user_data
, sc
);
186 GETATTR_ParrotInterpreter_interp(interp
, interp_pmc
, interp
);
188 UNLOCK(interpreter_array_mutex
);
190 PANIC(interp
, "interpreter not found for callback");
193 * 2) some more checks
194 * now we should have the interpreter where that callback
195 * did originate - do some further checks on the PMC
198 /* if that doesn't look like a PMC we are still lost */
199 if (!PObj_is_PMC_TEST(user_data
))
200 PANIC(interp
, "user_data isn't a PMC");
202 if (!user_data
->vtable
)
203 PANIC(interp
, "user_data hasn't a vtable");
207 callback_CD(interp
, external_data
, user_data
);
212 =item C<static void callback_CD(PARROT_INTERP, char *external_data, PMC
215 Common callback function handler. See pdd16.
222 callback_CD(PARROT_INTERP
, ARGIN(char *external_data
), ARGMOD(PMC
*user_data
))
224 ASSERT_ARGS(callback_CD
)
226 PMC
*passed_interp
; /* the interp that originated the CB */
227 PMC
*passed_synchronous
; /* flagging synchronous execution */
228 int synchronous
= 0; /* cb is hitting this sub somewhen
232 * 3) check interpreter ...
234 sc
= CONST_STRING(interp
, "_interpreter");
235 passed_interp
= VTABLE_getprop(interp
, user_data
, sc
);
236 if (VTABLE_get_pointer(interp
, passed_interp
) != interp
)
237 PANIC(interp
, "callback gone to wrong interpreter");
239 sc
= CONST_STRING(interp
, "_synchronous");
240 passed_synchronous
= VTABLE_getprop(interp
, user_data
, sc
);
241 if (!PMC_IS_NULL(passed_synchronous
) &&
242 VTABLE_get_bool(interp
, passed_synchronous
))
246 * 4) check if the call_back is synchronous:
247 * - if yes we are inside the NCI call
248 * we could run the Sub immediately now (I think)
249 * - if no, and that's always safe, post a callback event
256 Parrot_run_callback(interp
, user_data
, external_data
);
260 * create a CB_EVENT, put user_data and data inside and finito
262 * *if* this function is finally no void, i.e. the calling
263 * C program awaits a return result from the callback,
264 * then wait for the CB_EVENT_xx to finish and return the
267 Parrot_cx_schedule_callback(interp
, user_data
, external_data
);
273 =item C<void Parrot_run_callback(PARROT_INTERP, PMC* user_data, char*
276 Run a callback function. The PMC* user_data holds all
277 necessary items in its properties.
285 Parrot_run_callback(PARROT_INTERP
,
286 ARGMOD(PMC
* user_data
), ARGIN(char* external_data
))
288 ASSERT_ARGS(Parrot_run_callback
)
298 void *param
= NULL
; /* avoid -Ox warning */
301 sc
= CONST_STRING(interp
, "_sub");
302 sub
= VTABLE_getprop(interp
, user_data
, sc
);
303 sc
= CONST_STRING(interp
, "_signature");
304 signature
= VTABLE_getprop(interp
, user_data
, sc
);
306 sig_str
= VTABLE_get_string(interp
, signature
);
307 sig_cstr
= Parrot_str_to_cstring(interp
, sig_str
);
309 ++p
; /* Skip return type */
312 if (*p
== 'U') /* user_data Z in pdd16 */
313 ++p
; /* p is now type of external data */
319 i_param
= (INTVAL
)(long) external_data
;
322 i_param
= (INTVAL
)(int)(long) external_data
;
325 i_param
= (INTVAL
)(short)(long) external_data
;
328 i_param
= (INTVAL
)(char)(long)external_data
;
331 param
= (void*) i_param
;
334 /* created a UnManagedStruct */
335 p_param
= Parrot_pmc_new(interp
, enum_class_UnManagedStruct
);
336 VTABLE_set_pointer(interp
, p_param
, external_data
);
338 param
= (void*) p_param
;
342 param
= Parrot_str_new(interp
, external_data
, 0);
346 Parrot_str_free_cstring(sig_cstr
);
347 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
348 "unhandled signature char '%c' in run_cb", ch
);
350 Parrot_str_free_cstring(sig_cstr
);
352 pasm_sig
[3] = '>'; /* no return value supported yet */
354 Parrot_ext_call(interp
, sub
, pasm_sig
, user_data
, param
);
358 =item C<void Parrot_callback_C(char *external_data, PMC *user_data)>
360 =item C<void Parrot_callback_D(PMC *user_data, char *external_data)>
362 NCI callback functions. See pdd16.
370 Parrot_callback_C(ARGIN(char *external_data
), ARGMOD_NULLOK(PMC
*user_data
))
372 ASSERT_ARGS(Parrot_callback_C
)
373 verify_CD(external_data
, user_data
);
378 Parrot_callback_D(ARGMOD(PMC
*user_data
), ARGMOD_NULLOK(char *external_data
))
380 ASSERT_ARGS(Parrot_callback_D
)
381 verify_CD(external_data
, user_data
);
387 * c-file-style: "parrot"
389 * vim: expandtab shiftwidth=4: