@@ -251,9 +251,8 @@ fn main() {
251
251
252
252
# Callbacks from C code to Rust functions
253
253
254
- Some external libraries require the usage of callbacks.
255
- E.g. because they start background threads and use callbacks to signal events
256
- like the availability of new data.
254
+ Some external libraries require the usage of callbacks to report back their
255
+ current state or intermediate data to the caller.
257
256
It is possible to pass functions defined in Rust to an external library.
258
257
The requirement for this is that the callback function is marked as ` extern `
259
258
with the correct calling convention to make it callable from C code.
@@ -265,24 +264,25 @@ A basic example is:
265
264
266
265
Rust code:
267
266
~~~~
268
- extern "C" fn callback(a:i32) {
267
+ extern fn callback(a:i32) {
269
268
println!("I'm called from C with value {0}", a);
270
269
}
271
270
272
271
#[link(name = "extlib")]
273
272
extern {
274
273
fn register_callback(cb: extern "C" fn(i32)) -> i32;
274
+ fn trigger_callback();
275
275
}
276
276
277
277
fn main() {
278
278
unsafe {
279
279
register_callback(callback);
280
+ trigger_callback(); // Triggers the callback
280
281
}
281
- ... // Do sth. and wait for callbacks
282
282
}
283
283
~~~~
284
284
285
- C-Code :
285
+ C code :
286
286
~~~~
287
287
typedef void (*rust_callback)(int32_t);
288
288
rust_callback cb;
@@ -292,15 +292,14 @@ int32_t register_callback(rust_callback callback) {
292
292
return 1;
293
293
}
294
294
295
- void thread() {
296
- // do sth
295
+ void trigger_callback() {
297
296
cb(7); // Will call callback(7) in Rust
298
297
}
299
298
~~~~
300
299
301
- Keep in mind that ` callback ()` will be called from a C thread and not from
302
- a Rust thread or even your main thread. Therefore each data access is
303
- especially unsafe and synchronization mechanisms must be used.
300
+ In this example will Rust's ` main ()` will call ` do_callback() ` in C,
301
+ which would call back to ` callback() ` in Rust.
302
+
304
303
305
304
## Targetting callbacks to Rust objects
306
305
@@ -314,115 +313,78 @@ C library. The C library can then include the pointer to the Rust object in
314
313
the notification. This will provide a unsafe possibility to access the
315
314
referenced Rust object in callback.
316
315
317
- If this mechanism is used it is absolutely necessary that no more callbacks
318
- are performed by C library after the respective Rust object get's
319
- destroyed. This can be achieved by unregistering the callback it the object's
320
- destructor and designing the library in a way that guarantees that no
321
- callback will be performed after unregistration.
322
-
323
- ## Sychronzing callbacks with channels
324
-
325
- As already explained accessing data of a Rust object in a callback is unsafe
326
- without synchronisation. Channels in Rust provide a mechanism
327
- which can be used to forward events into Rust tasks. The idea is to create a
328
- channel where the writing end (` Chan ` ) is used exclusively from the C callback
329
- to queue events. The reading end (` Port ` ) is used in the Rust task which owns
330
- the wrapper object.
331
-
332
- Depending on the type of data in the event you might want to convert callback
333
- data from C into a more suitable Rust structure before sending it into the
334
- channel. E.g. it makes sense to convert C strings (` char* ` ) into Rust strings.
335
- You could also use Rust enumerations to differentiate between multiple types
336
- of events and their data.
337
-
338
- Putting this together a wrapper for a library that uses a background thread
339
- that sends events could look like:
340
-
341
316
Rust code:
342
317
~~~~
343
318
344
- #[link(name = "extlib")]
345
- extern {
346
- fn init(target: *ExtLibWrapper, cb: extern "C" fn(*ExtLibWrapper, EventData));
347
- fn unregister();
348
- }
349
-
350
- struct EventData {
351
- ... // Contains data that describes the event
319
+ struct RustObject {
320
+ a: i32,
321
+ // other members
352
322
}
353
323
354
- pub struct ExtLibWrapper {
355
- // Channel is used privately
356
- priv chan: comm::Chan<EventData>,
357
-
358
- // The port is used by the Rust task to receive notifications
359
- port: comm::Port<EventData>
360
- }
361
-
362
- impl ExtLibWrapper {
363
- pub fn new() -> ~ EventData {
364
- let (p,c):(Port<EventData>,Chan<EventData>)
365
- = comm::Chan::new();
366
-
367
- let wrapper = ~ExtLibWrapper{chan:c, port:p};
368
-
369
- unsafe {
370
- let wrapper_addr:*ExtLibWrapper = ptr::to_unsafe_ptr(wrapper);
371
- init(wrapper_addr, callback);
372
- }
373
- }
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
374
327
}
375
328
376
- impl Drop for ExtLibWrapper {
377
- fn drop(&mut self) {
378
- // Unregister to avoid further callbacks
379
- unsafe { unregister(); }
380
- }
329
+ #[link(name = "extlib")]
330
+ extern {
331
+ fn register_callback(target: *RustObject, cb: extern "C" fn(*RustObject, i32)) -> i32;
332
+ fn trigger_callback();
381
333
}
382
334
383
- extern "C" fn callback(target: *ExtLibWrapper, data: EventData) {
384
- unsafe {
385
- (*target).chan.send(data); // Forward the event data through channel
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
386
344
}
387
345
}
388
346
~~~~
389
347
390
- C-Code :
348
+ C code :
391
349
~~~~
392
- typedef void (*rust_callback)(void* target, EventData data );
393
- void* rust_target ;
350
+ typedef void (*rust_callback)(int32_t );
351
+ void* cb_target ;
394
352
rust_callback cb;
395
- mutex mtx; // Example mutex
396
353
397
- void init (void* target , rust_callback callback) {
398
- rust_target = target ;
354
+ int32_t register_callback (void* callback_target , rust_callback callback) {
355
+ cb_target = callback_target ;
399
356
cb = callback;
357
+ return 1;
400
358
}
401
359
402
- void background_thread() {
403
- // do sth
404
-
405
- // Lock the mutex to guarantee that callback is not performed after Rust
406
- // object is destroyed
407
- mutex_lock(mtx);
408
- if (rust_target != 0) cb(rust_target, event_data);
409
- mutex_unlock(mtx);
410
-
411
- // do sth
412
- }
413
-
414
- void unregister() {
415
- mutex_lock(mtx);
416
- rust_target = 0;
417
- mutex_unlock(mtx);
360
+ void trigger_callback() {
361
+ cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
418
362
}
419
363
~~~~
420
364
421
- Remark: This example will not work correctly if more than a single
422
- ` ExtLibWrapper ` object is created. If this is required additional handles
423
- have to be introduced which identify each object. E.g. ` ExtLibWrapper ` would
424
- have to store the member of the associated C object as member and pass it
425
- on each function call.
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.
426
388
427
389
# Linking
428
390
0 commit comments