@@ -720,11 +720,10 @@ En C par exemple, il n'y a pas de moyen simple qui permette de vérifier que le
720720destructeur correspondant est appelé. Il est possible d'utiliser des _ callbacks_
721721pour assurer que la libération est effectivement faite.
722722
723- Le code Rust suivant est un exemple ** _ unsafe_ du point de vue des threads**
724- d'une API compatible avec le C qui fournit une _ callback_ pour assurer la
725- libération d'une ressource :
723+ Le code Rust suivant est un exemple d'une API compatible avec le C qui exploite
724+ les _ callbacks_ pour assurer la libération d'une ressource :
726725
727- ``` rust,noplaypen
726+ ``` rust
728727# use std :: ops :: Drop ;
729728#
730729pub struct XtraResource { /* champs */ }
@@ -733,8 +732,12 @@ impl XtraResource {
733732 pub fn new () -> Self {
734733 XtraResource { /* ... */ }
735734 }
736- pub fn dosthg(&mut self) {
737- /* ... */
735+
736+ pub fn dosthg (& mut self , arg : u32 ) {
737+ /*... des choses qui peuvent paniquer ... */
738+ # if arg == 0xDEAD_C0DE {
739+ # panic! (" oups XtraResource.dosthg panique!" );
740+ # }
738741 }
739742}
740743
@@ -746,58 +749,55 @@ impl Drop for XtraResource {
746749
747750pub mod c_api {
748751 use super :: XtraResource ;
749- use std::panic::catch_unwind;
752+ use std :: panic :: {catch_unwind, AssertUnwindSafe };
753+ use std :: sync :: atomic :: {AtomicU32 , Ordering };
750754
751755 const INVALID_TAG : u32 = 0 ;
752756 const VALID_TAG : u32 = 0xDEAD_BEEF ;
753757 const ERR_TAG : u32 = 0xDEAF_CAFE ;
754758
755- static mut COUNTER: u32 = 0;
756-
757759 pub struct CXtraResource {
758- tag: u32, // pour prévenir d'une réutilisation accidentelle
759- id: u32,
760+ tag : AtomicU32 , // pour prévenir d'une réutilisation accidentelle
760761 inner : XtraResource ,
761762 }
762763
763764 #[no_mangle]
764- pub unsafe extern "C" fn xtra_with(cb: extern "C" fn(*mut CXtraResource) -> ()) {
765- let inner = if let Ok(res) = catch_unwind(XtraResource::new) {
765+ pub unsafe extern " C" fn xtra_with (cb : unsafe extern " C" fn (* mut CXtraResource ) -> ()) {
766+ let inner = if let Ok (res ) = catch_unwind (AssertUnwindSafe ( XtraResource :: new ) ) {
766767 res
767768 } else {
768769# println! (" impossible d'allouer la ressource" );
769770 return ;
770771 };
771- let id = COUNTER;
772772 let tag = VALID_TAG ;
773773
774- COUNTER = COUNTER.wrapping_add(1);
775- // Utilisation de la mémoire du tas pour ne pas fournir de pointeur de
776- // pile au code C!
777- let mut boxed = Box::new(CXtraResource { tag, id, inner }) ;
774+ let mut wrapped = CXtraResource {
775+ tag : AtomicU32 :: new ( tag ),
776+ inner
777+ } ;
778778
779- # println!("running the callback on {:p}", boxed.as_ref() );
780- cb(boxed.as_mut() as *mut CXtraResource);
779+ # println! (" appel du callback sur {:p}" , & wrapped );
780+ cb (& mut wrapped as * mut CXtraResource );
781781
782- if boxed.id == id && (boxed.tag == VALID_TAG || boxed.tag == ERR_TAG) {
783- # println!("freeing {:p}", boxed.as_ref());
784- boxed.tag = INVALID_TAG; // prévention d'une réutilisation accidentelle
785- // drop implicite de la `box`
782+ // pour éviter de réutilisation accidentelle
783+ let new_tag = wrapped . tag. swap (INVALID_TAG , Ordering :: SeqCst );
784+ if new_tag == VALID_TAG || new_tag == ERR_TAG {
785+ # println! (" libération de {:p}" , & wrapped );
786+ // drop implicite de la `box`
786787 } else {
787- # println!("oubli de {:p}", boxed.as_ref() );
788+ # println! (" oubli de {:p}" , & wrapped );
788789 // (...) gestion des erreurs (partie critique)
789- boxed.tag = INVALID_TAG; // prévention d'une réutilisation
790- std::mem::forget(boxed); // boxed is corrupted it should not be
790+ std :: mem :: forget (wrapped ); // la boîte est corrompu, ne pas libérer!
791791 }
792792 }
793793
794794 #[no_mangle]
795- pub unsafe extern "C" fn xtra_dosthg(cxtra: *mut CXtraResource) {
796- let do_it = || {
795+ pub unsafe extern " C" fn xtra_dosthg (cxtra : * mut CXtraResource , arg : u32 ) {
796+ let do_it = move || {
797797 if let Some (cxtra ) = cxtra . as_mut () {
798- if cxtra.tag == VALID_TAG {
799- # println!("doing something with {:p}", cxtra);
800- cxtra.inner.dosthg();
798+ if cxtra . tag. load ( Ordering :: SeqCst ) == VALID_TAG {
799+ # println! (" fait quelque chose avec {:p}" , cxtra );
800+ cxtra . inner. dosthg (arg );
801801 return ;
802802 }
803803 }
@@ -806,25 +806,40 @@ pub mod c_api {
806806 if catch_unwind (do_it ). is_err () {
807807 if let Some (cxtra ) = cxtra . as_mut () {
808808# println! (" panic avec {:p}" , cxtra );
809- cxtra.tag = ERR_TAG;
809+ cxtra . tag. store ( ERR_TAG , Ordering :: SeqCst ) ;
810810 }
811811 };
812812 }
813813}
814814#
815- # fn main() {}
815+ # fn main () {
816+ # // ne pas utiliser, seulement pour le test
817+ # use c_api :: * ;
818+ # unsafe {
819+ # unsafe extern " C" fn cb_ok (p : * mut CXtraResource ) {
820+ # xtra_dosthg (p , 0 );
821+ # }
822+ # unsafe extern " C" fn cb_panic (p : * mut CXtraResource ) {
823+ # xtra_dosthg (p , 0xDEADC0DE );
824+ # }
825+ # xtra_with (cb_ok );
826+ # xtra_with (cb_panic );
827+ # }
828+ # }
816829```
817830
818831Un appel C compatible :
819832
820833``` c
834+ #include < stdint.h>
835+
821836struct XtraResource;
822- void xtra_with (void (* cb)(XtraResource* xtra));
837+ void xtra_with (void (* cb)(XtraResource* xtra), uint32_t arg );
823838void xtra_sthg(XtraResource* xtra);
824839
825840void cb(XtraResource* xtra) {
826841 // ()...) do anything with the proposed C API for XtraResource
827- xtra_sthg(xtra);
842+ xtra_sthg(xtra, 0 );
828843}
829844
830845int main() {
0 commit comments