* docs/pmc.pod:
[parrot.git] / src / inter_cb.c
blob3b7953ffc7b9215fde7b54a153114ee510b07684
1 /*
2 Copyright (C) 2001-2003, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/inter_cb.c - Parrot Interpreter - Callback Function Handling
9 =head1 DESCRIPTION
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
13 events.
15 Often callbacks should run synchronously. This can only happen when
16 the C-library calls the callback, because Parrot called a function in
17 the C-library.
19 =head2 Functions
21 =over 4
23 =cut
27 #include <assert.h>
28 #include "parrot/parrot.h"
29 #include "inter_cb.str"
34 =item C<PMC* Parrot_make_cb(Parrot_Interp interpreter, PMC* sub, PMC* user
35 STRING* cb_signature)>
37 Create a callback function according to pdd16.
39 =cut
43 PMC*
44 Parrot_make_cb(Parrot_Interp interpreter, PMC* sub, PMC* user_data,
45 STRING *cb_signature)
47 PMC* interp_pmc, *cb, *cb_sig;
48 int type = '?'; /* avoid -Ox warning */
49 char * sig_str;
50 STRING *sc;
52 * we stuff all the information into the user_data PMC and pass that
53 * on to the external sub
55 interp_pmc = VTABLE_get_pmc_keyed_int(interpreter, interpreter->iglobals,
56 (INTVAL) IGLOBALS_INTERPRETER);
57 /* be sure __LINE__ is consistent */
58 sc = CONST_STRING(interpreter, "_interpreter");
59 VTABLE_setprop(interpreter, user_data, sc, interp_pmc);
60 sc = CONST_STRING(interpreter, "_sub");
61 VTABLE_setprop(interpreter, user_data, sc, sub);
62 /* only ASCII signatures are supported */
63 sig_str = cb_signature->strstart;
65 if (strlen (sig_str) != 3) {
66 internal_exception(1, "unhandled signature '%s' in make_cb",
67 cb_signature->strstart);
70 ++sig_str; /* Skip callback return type */
72 if (*sig_str == 'U') {
73 type = 'D';
75 else {
76 ++sig_str;
77 if (*sig_str == 'U') {
78 type = 'C';
80 else {
81 internal_exception(1, "unhandled signature '%s' in make_cb",
82 cb_signature->strstart);
86 cb_sig = pmc_new(interpreter, enum_class_String);
87 VTABLE_set_string_native(interpreter, cb_sig, cb_signature);
88 sc = CONST_STRING(interpreter, "_signature");
89 VTABLE_setprop(interpreter, user_data, sc, cb_sig);
91 * We are going to be passing the user_data PMC to external code, but
92 * it may go out of scope until the callback is called -- we don't know
93 * for certain as we don't know when the callback will be called.
94 * Therefore, to prevent the PMC from being destroyed by a DOD sweep,
95 * we need to anchor it.
98 dod_register_pmc(interpreter, user_data);
101 * Finally, the external lib awaits a function pointer.
102 * Create a PMC that points to Parrot_callback_C (or _D);
103 * it can be passed on with signature 'p'.
105 cb = pmc_new(interpreter, enum_class_UnManagedStruct);
107 * Currently, we handle only 2 types:
108 * _C ... user_data is 2nd parameter
109 * _D ... user_data is 1st parameter
111 if (type == 'C')
112 PMC_data(cb) = F2DPTR(Parrot_callback_C);
113 else
114 PMC_data(cb) = F2DPTR(Parrot_callback_D);
115 dod_register_pmc(interpreter, cb);
117 return cb;
122 =item C<static void verify_CD(void *external_data, PMC *user_data)>
124 Verify user_data PMC then continue with callback_CD
126 =cut
130 static void callback_CD(Parrot_Interp, void *, PMC *user_data);
132 static void
133 verify_CD(void *external_data, PMC *user_data)
135 Parrot_Interp interpreter = NULL;
136 size_t i;
139 * 1.) user_data is from external code so:
140 * verify that we get a PMC that is one that we have passed in
141 * as user data, when we prepared the callback
144 /* a NULL pointer or a pointer not aligned is very likely wrong */
145 if (!user_data || ((UINTVAL)user_data & 3))
146 PANIC("user_data doesn't look like a pointer");
149 * We don't yet know which interpreter this PMC is from, so run
150 * through all of the existing interpreters and check their PMC
151 * pools
153 LOCK(interpreter_array_mutex);
154 for (i = 0; i < n_interpreters; ++i) {
155 if (interpreter_array[i] == NULL)
156 continue;
157 interpreter = interpreter_array[i];
158 if (interpreter)
159 if (contained_in_pool(interpreter,
160 interpreter->arena_base->pmc_pool, user_data))
161 break;
163 UNLOCK(interpreter_array_mutex);
164 if (!interpreter)
165 PANIC("interpreter not found for callback");
168 * 2) some more checks
169 * now we should have the interpreter where that callback
170 * did originate - do some further checks on the PMC
173 /* if that doesn't look like a PMC we are still lost */
174 if (!PObj_is_PMC_TEST(user_data))
175 PANIC("user_data isn't a PMC");
177 if (!user_data->vtable)
178 PANIC("user_data hasn't a vtable");
180 * ok fine till here
182 callback_CD(interpreter, external_data, user_data);
187 =item C<static void
188 callback_CD(Parrot_Interp, void *external_data, PMC *user_data)>
190 Common callback function handler. See pdd16.
192 =cut
196 static void
197 callback_CD(Parrot_Interp interpreter, void *external_data, PMC *user_data)
200 PMC *passed_interp; /* the interp that originated the CB */
201 PMC *passed_synchronous; /* flagging synchronous execution */
202 int synchronous = 0; /* cb is hitting this sub somewhen
203 * inmidst, or not */
204 STRING *sc;
206 * 3) check interpreter ...
208 sc = CONST_STRING(interpreter, "_interpreter");
209 passed_interp = VTABLE_getprop(interpreter, user_data, sc);
210 if (PMC_data(passed_interp) != interpreter)
211 PANIC("callback gone to wrong interpreter");
213 sc = CONST_STRING(interpreter, "_synchronous");
214 passed_synchronous = VTABLE_getprop(interpreter, user_data, sc);
215 if (!PMC_IS_NULL(passed_synchronous) &&
216 VTABLE_get_bool(interpreter, passed_synchronous))
217 synchronous = 1;
220 * 4) check if the call_back is synchronous:
221 * - if yes we are inside the NCI call
222 * we could run the Sub immediately now (I think)
223 * - if no, and that's always safe, post a CALLBACK_EVENT
226 if ( synchronous ) {
228 * just call the sub
230 Parrot_run_callback(interpreter, user_data, external_data);
232 else {
234 * create a CB_EVENT, put user_data and data inside and finito
236 * *if* this function is finally no void, i.e. the calling
237 * C program awaits a return result from the callback,
238 * then wait for the CB_EVENT_xx to finish and return the
239 * result
241 Parrot_new_cb_event(interpreter, user_data, external_data);
247 =item C<void
248 Parrot_run_callback(Parrot_Interp interpreter,
249 PMC* user_data, void* external_data)>
251 Run a callback function. The PMC* user_data holds all
252 necessary items in its properties.
254 =cut
258 void
259 Parrot_run_callback(Parrot_Interp interpreter,
260 PMC* user_data, void* external_data)
262 PMC * signature;
263 PMC * sub;
264 STRING * sig_str;
265 char * p;
266 char pasm_sig[4];
267 INTVAL i_param;
268 PMC * p_param;
269 void* param = NULL; /* avoid -Ox warning */
270 STRING * sc;
272 sc = CONST_STRING(interpreter, "_sub");
273 sub = VTABLE_getprop(interpreter, user_data, sc);
274 sc = CONST_STRING(interpreter, "_signature");
275 signature = VTABLE_getprop(interpreter, user_data, sc);
277 sig_str = VTABLE_get_string(interpreter, signature);
278 p = sig_str->strstart;
279 ++p; /* Skip return type */
281 pasm_sig[0] = 'v'; /* no return value supported yet */
282 pasm_sig[1] = 'P';
283 if (*p == 'U') /* user_data Z in pdd16 */
284 ++p; /* p is now type of external data */
285 switch (*p) {
286 case 'v':
287 pasm_sig[2] = 'v';
288 break;
289 #if 0
290 case '2':
291 case '3':
292 case '4':
293 #endif
294 case 'l':
295 i_param = (INTVAL)(long) external_data;
296 goto case_I;
297 case 'i':
298 i_param = (INTVAL)(int)(long) external_data;
299 goto case_I;
300 case 's':
301 i_param = (INTVAL)(short)(long) external_data;
302 goto case_I;
303 case 'c':
304 i_param = (INTVAL)(char)(long)external_data;
305 case_I:
306 pasm_sig[2] = 'I';
307 param = (void*) i_param;
308 break;
309 #if 0
310 case 'f':
311 case 'd':
312 /* these types don't fit into a pointer, they will not
313 * work
315 break;
316 #endif
317 case 'p':
318 /* created a UnManagedStruct */
319 p_param = pmc_new(interpreter, enum_class_UnManagedStruct);
320 PMC_data(p_param) = external_data;
321 pasm_sig[2] = 'P';
322 param = (void*) p_param;
323 break;
324 #if 0
325 case 'P':
326 pasm_sig[2] = 'P';
327 break;
328 #endif
329 case 't':
330 pasm_sig[2] = 'S';
331 param = string_from_cstring(interpreter, external_data, 0);
332 break;
333 default:
334 internal_exception(1, "unhandled signature char '%c' in run_cb",
335 *p);
337 pasm_sig[3] = '\0';
338 Parrot_runops_fromc_args_event(interpreter, sub, pasm_sig,
339 user_data, param);
343 =item C<void Parrot_callback_C(void *external_data, PMC *user_data)>
345 =item C<void Parrot_callback_D(PMC *user_data, void *external_data)>
347 NCI callback functions. See pdd16.
349 =cut
353 void
354 Parrot_callback_C(void *external_data, PMC *user_data)
356 verify_CD(external_data, user_data);
359 void
360 Parrot_callback_D(PMC *user_data, void *external_data)
362 verify_CD(external_data, user_data);
367 =back
369 =head1 SEE ALSO
371 F<include/parrot/interpreter.h>, F<docs/pdds/pdd16_native_call.pod>.
373 =cut
379 * Local variables:
380 * c-file-style: "parrot"
381 * End:
382 * vim: expandtab shiftwidth=4: