Skip to content

Commit 0b40308

Browse files
committed
---
yaml --- r: 148468 b: refs/heads/try2 c: 40df5a2 h: refs/heads/master v: v3
1 parent 12ba0c6 commit 0b40308

File tree

10 files changed

+209
-6
lines changed

10 files changed

+209
-6
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: cb12de14c92526930aa9c55e660fe2f7350fb56a
8+
refs/heads/try2: 40df5a2e9ac81f445c7122a484618918b752a1e2
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/doc/guide-ffi.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,143 @@ fn main() {
249249
}
250250
~~~~
251251

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+
252389
# Linking
253390

254391
The `link` attribute on `extern` blocks provides the basic building block for

branches/try2/doc/rust.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ include:
484484

485485
* `fmt!` : format data into a string
486486
* `env!` : look up an environment variable's value at compile time
487+
* `file!`: return the path to the file being compiled
487488
* `stringify!` : pretty-print the Rust expression given as an argument
488489
* `include!` : include the Rust expression in the given file
489490
* `include_str!` : include the contents of the given file as a string

branches/try2/src/librustc/metadata/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,7 @@ impl<'a, 'b> Visitor<()> for MacroDefVisitor<'a, 'b> {
17201720
}
17211721
_ => {}
17221722
}
1723+
visit::walk_item(self, item, ());
17231724
}
17241725
}
17251726

branches/try2/src/librustc/middle/borrowck/doc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ checker uses a data flow propagation to compute the full set of loans
179179
in scope at each expression and then uses that set to decide whether
180180
that expression is legal. Remember that the scope of loan is defined
181181
by its lifetime LT. We sometimes say that a loan which is in-scope at
182-
a particular point is an "outstanding loan", aand the set of
182+
a particular point is an "outstanding loan", and the set of
183183
restrictions included in those loans as the "outstanding
184184
restrictions".
185185

branches/try2/src/librustc/middle/check_const.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,10 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
177177
}
178178
}
179179
}
180-
ExprParen(e) => { check_expr(v, sess, def_map, method_map,
181-
tcx, e, is_const); }
182180
ExprVstore(_, ExprVstoreSlice) |
183181
ExprVec(_, MutImmutable) |
184182
ExprAddrOf(MutImmutable, _) |
183+
ExprParen(..) |
185184
ExprField(..) |
186185
ExprIndex(..) |
187186
ExprTup(..) |

branches/try2/src/librustc/middle/moves.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ case, the value is read, and the container (`x`) is also read.
3838
In the second case, `y`, `x.b` is being assigned which has type
3939
`~int`. Because this type moves by default, that will be a move
4040
reference. Whenever we move from a compound expression like `x.b` (or
41-
`x[b]` or `*x` or `{x)[b].c`, etc), this invalidates all containing
41+
`x[b]` or `*x` or `{x}[b].c`, etc), this invalidates all containing
4242
expressions since we do not currently permit "incomplete" variables
4343
where part of them has been moved and part has not. In this case,
4444
this means that the reference to `x` is also a move. We'll see later,
@@ -56,7 +56,7 @@ For each binding in a match or let pattern, we also compute a read
5656
or move designation. A move binding means that the value will be
5757
moved from the value being matched. As a result, the expression
5858
being matched (aka, the 'discriminant') is either moved or read
59-
depending on whethe the bindings move the value they bind to out of
59+
depending on whether the bindings move the value they bind to out of
6060
the discriminant.
6161
6262
For examples, consider this match expression:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[feature(macro_rules)];
12+
13+
pub mod inner {
14+
#[macro_export]
15+
macro_rules! foo(
16+
() => (1)
17+
)
18+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//aux-build:macro_export_inner_module.rs
12+
//xfail-stage1
13+
//xfail-fast
14+
15+
#[feature(phase)];
16+
17+
#[phase(syntax)]
18+
extern mod macro_export_inner_module;
19+
20+
pub fn main() {
21+
assert_eq!(1, foo!());
22+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
static a: int =
12+
(((((((((((((((((((((((((((((((((((((((((((((((((((
13+
(((((((((((((((((((((((((((((((((((((((((((((((((((
14+
(((((((((((((((((((((((((((((((((((((((((((((((((((
15+
(((((((((((((((((((((((((((((((((((((((((((((((((((
16+
(((((((((((((((((((((((((((((((((((((((((((((((((((
17+
1
18+
)))))))))))))))))))))))))))))))))))))))))))))))))))
19+
)))))))))))))))))))))))))))))))))))))))))))))))))))
20+
)))))))))))))))))))))))))))))))))))))))))))))))))))
21+
)))))))))))))))))))))))))))))))))))))))))))))))))))
22+
)))))))))))))))))))))))))))))))))))))))))))))))))))
23+
;
24+
25+
pub fn main() {}

0 commit comments

Comments
 (0)