2 Copyright (C) 2001-2003, The Perl Foundation.
7 src/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
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.
44 Parrot_make_cb(Parrot_Interp interpreter
, PMC
* sub
, PMC
* user_data
,
47 PMC
* interp_pmc
, *cb
, *cb_sig
;
48 int type
= '?'; /* avoid -Ox warning */
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') {
77 if (*sig_str
== 'U') {
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
112 PMC_data(cb
) = F2DPTR(Parrot_callback_C
);
114 PMC_data(cb
) = F2DPTR(Parrot_callback_D
);
115 dod_register_pmc(interpreter
, cb
);
122 =item C<static void verify_CD(void *external_data, PMC *user_data)>
124 Verify user_data PMC then continue with callback_CD
130 static void callback_CD(Parrot_Interp
, void *, PMC
*user_data
);
133 verify_CD(void *external_data
, PMC
*user_data
)
135 Parrot_Interp interpreter
= NULL
;
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
153 LOCK(interpreter_array_mutex
);
154 for (i
= 0; i
< n_interpreters
; ++i
) {
155 if (interpreter_array
[i
] == NULL
)
157 interpreter
= interpreter_array
[i
];
159 if (contained_in_pool(interpreter
,
160 interpreter
->arena_base
->pmc_pool
, user_data
))
163 UNLOCK(interpreter_array_mutex
);
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");
182 callback_CD(interpreter
, external_data
, user_data
);
188 callback_CD(Parrot_Interp, void *external_data, PMC *user_data)>
190 Common callback function handler. See pdd16.
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
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
))
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
230 Parrot_run_callback(interpreter
, user_data
, external_data
);
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
241 Parrot_new_cb_event(interpreter
, user_data
, external_data
);
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.
259 Parrot_run_callback(Parrot_Interp interpreter
,
260 PMC
* user_data
, void* external_data
)
269 void* param
= NULL
; /* avoid -Ox warning */
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 */
283 if (*p
== 'U') /* user_data Z in pdd16 */
284 ++p
; /* p is now type of external data */
295 i_param
= (INTVAL
)(long) external_data
;
298 i_param
= (INTVAL
)(int)(long) external_data
;
301 i_param
= (INTVAL
)(short)(long) external_data
;
304 i_param
= (INTVAL
)(char)(long)external_data
;
307 param
= (void*) i_param
;
312 /* these types don't fit into a pointer, they will not
318 /* created a UnManagedStruct */
319 p_param
= pmc_new(interpreter
, enum_class_UnManagedStruct
);
320 PMC_data(p_param
) = external_data
;
322 param
= (void*) p_param
;
331 param
= string_from_cstring(interpreter
, external_data
, 0);
334 internal_exception(1, "unhandled signature char '%c' in run_cb",
338 Parrot_runops_fromc_args_event(interpreter
, sub
, pasm_sig
,
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.
354 Parrot_callback_C(void *external_data
, PMC
*user_data
)
356 verify_CD(external_data
, user_data
);
360 Parrot_callback_D(PMC
*user_data
, void *external_data
)
362 verify_CD(external_data
, user_data
);
371 F<include/parrot/interpreter.h>, F<docs/pdds/pdd16_native_call.pod>.
380 * c-file-style: "parrot"
382 * vim: expandtab shiftwidth=4: