@@ -249,6 +249,143 @@ fn main() {
249
249
}
250
250
~~~~
251
251
252
+ # Callbacks from C code to Rust functions
253
+
254
+ Some external libraries require the usage of callbacks to report back their
255
+ current state or intermediate data to the caller.
256
+ It is possible to pass functions defined in Rust to an external library.
257
+ The requirement for this is that the callback function is marked as ` extern `
258
+ with the correct calling convention to make it callable from C code.
259
+
260
+ The callback function that can then be sent to through a registration call
261
+ to the C library and afterwards be invoked from there.
262
+
263
+ A basic example is:
264
+
265
+ Rust code:
266
+ ~~~~ {.xfail-test}
267
+ extern fn callback(a:i32) {
268
+ println!("I'm called from C with value {0}", a);
269
+ }
270
+
271
+ #[link(name = "extlib")]
272
+ extern {
273
+ fn register_callback(cb: extern "C" fn(i32)) -> i32;
274
+ fn trigger_callback();
275
+ }
276
+
277
+ fn main() {
278
+ unsafe {
279
+ register_callback(callback);
280
+ trigger_callback(); // Triggers the callback
281
+ }
282
+ }
283
+ ~~~~
284
+
285
+ C code:
286
+ ~~~~ {.xfail-test}
287
+ typedef void (*rust_callback)(int32_t);
288
+ rust_callback cb;
289
+
290
+ int32_t register_callback(rust_callback callback) {
291
+ cb = callback;
292
+ return 1;
293
+ }
294
+
295
+ void trigger_callback() {
296
+ cb(7); // Will call callback(7) in Rust
297
+ }
298
+ ~~~~
299
+
300
+ In this example will Rust's ` main() ` will call ` do_callback() ` in C,
301
+ which would call back to ` callback() ` in Rust.
302
+
303
+
304
+ ## Targetting callbacks to Rust objects
305
+
306
+ The former example showed how a global function can be called from C-Code.
307
+ However it is often desired that the callback is targetted to a special
308
+ Rust object. This could be the object that represents the wrapper for the
309
+ respective C object.
310
+
311
+ This can be achieved by passing an unsafe pointer to the object down to the
312
+ C library. The C library can then include the pointer to the Rust object in
313
+ the notification. This will provide a unsafe possibility to access the
314
+ referenced Rust object in callback.
315
+
316
+ Rust code:
317
+ ~~~~ {.xfail-test}
318
+
319
+ struct RustObject {
320
+ a: i32,
321
+ // other members
322
+ }
323
+
324
+ extern fn callback(target: *RustObject, a:i32) {
325
+ println!("I'm called from C with value {0}", a);
326
+ (*target).a = a; // Update the value in RustObject with the value received from the callback
327
+ }
328
+
329
+ #[link(name = "extlib")]
330
+ extern {
331
+ fn register_callback(target: *RustObject, cb: extern "C" fn(*RustObject, i32)) -> i32;
332
+ fn trigger_callback();
333
+ }
334
+
335
+ fn main() {
336
+ // Create the object that will be referenced in the callback
337
+ let rust_object = ~RustObject{a: 5, ...};
338
+
339
+ unsafe {
340
+ // Gets a raw pointer to the object
341
+ let target_addr:*RustObject = ptr::to_unsafe_ptr(rust_object);
342
+ register_callback(target_addr, callback);
343
+ trigger_callback(); // Triggers the callback
344
+ }
345
+ }
346
+ ~~~~
347
+
348
+ C code:
349
+ ~~~~ {.xfail-test}
350
+ typedef void (*rust_callback)(int32_t);
351
+ void* cb_target;
352
+ rust_callback cb;
353
+
354
+ int32_t register_callback(void* callback_target, rust_callback callback) {
355
+ cb_target = callback_target;
356
+ cb = callback;
357
+ return 1;
358
+ }
359
+
360
+ void trigger_callback() {
361
+ cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
362
+ }
363
+ ~~~~
364
+
365
+ ## Asynchronous callbacks
366
+
367
+ In the already given examples the callbacks are invoked as a direct reaction
368
+ to a function call to the external C library.
369
+ The control over the current thread switched from Rust to C to Rust for the
370
+ execution of the callback, but in the end the callback is executed on the
371
+ same thread (and Rust task) that lead called the function which triggered
372
+ the callback.
373
+
374
+ Things get more complicated when the external library spawns it's own threads
375
+ and invokes callbacks from there.
376
+ In these cases access to Rust data structures inside he callbacks is
377
+ especially unsafe and proper synchronization mechanisms must be used.
378
+ Besides classical synchronization mechanisms like mutexes one possibility in
379
+ Rust is to use channels (in ` std::comm ` ) to forward data from the C thread
380
+ that invoked the callback into a Rust task.
381
+
382
+ If an asychronous callback targets a special object in the Rust address space
383
+ it is also absolutely necessary that no more callbacks are performed by the
384
+ C library after the respective Rust object get's destroyed.
385
+ This can be achieved by unregistering the callback it the object's
386
+ destructor and designing the library in a way that guarantees that no
387
+ callback will be performed after unregistration.
388
+
252
389
# Linking
253
390
254
391
The ` link ` attribute on ` extern ` blocks provides the basic building block for
0 commit comments