0

I'm trying to keep track of the number of instances of my C wrapper have been initialized.

I'm using std::sync::Once to initialize the C library a single time and I need to be able to call terminate once all instances have gone out of scope.

Currently, I have

static INSTANCES: usize = 0;
static mut VERSION: i32 = 0;
static GPIO_INIT: Once = ONCE_INIT;

fn init_gpio_lib() -> i32 {
    println!("GPIOs initialized.");
    64
}

fn terminate_gpio_lib() {
    println!("GPIO lib terminated!");
}

struct GPIO {
    version: i32
}

impl GPIO {
    fn init() -> GPIO {
        GPIO_INIT.call_once(|| {
            unsafe {
                VERSION = init_gpio_lib();        
            }
        });


        unsafe {
            INSTANCES += 1;
        }

        unsafe {
            GPIO {
                version: VERSION
            }
        }

    }

    fn terminate(&mut self) {
        unsafe {
            INSTANCES -= 1;
            if INSTANCES == 0 {
                terminate_gpio_lib();
            }
        }
    }
}

impl Drop for GPIO {
    fn drop(&mut self) {
        self.terminate();
    }
}

I'm trying to make it safe, but I can't figure out how. The two things I've tried are

  1. static INSTANCES: Mutex<usize> = Mutex::new(0) In this case, I can't call Mutex::new(0) here.
  2. lazy_static!{ static ref INSTANCES: Mutex<usize> = Mutex::new(0) } In this case, I can't use INSTANCES inside of a struct function call.
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • *and I need to be able to call `terminate` once all instances have gone out of scope.* — and what happens if the outer application then decides to create another instance? *I can't use `INSTANCES` inside of a struct function call.* — you certainly can, as the duplicate shows. – Shepmaster Nov 15 '17 at 03:02
  • I will call `GPIO_INIT = Once::new();` right after terminating. – Martin Deegan Nov 15 '17 at 03:06
  • Can you explain why in the `lazy_static` implementation inside `GPIO::init` I get the error `cannot find value 'INSTANCES' in this scope`? Shouldn't this be global? – Martin Deegan Nov 15 '17 at 03:10
  • Because of normal variable scoping rules. If you declare a variable inside a function, only that function can see it. A variable needs to be declared outside of functions if multiple functions need to see it. The variable itself continues to live beyond the function, it's just not accessible. – Shepmaster Nov 15 '17 at 03:12
  • I'm confused. In the post you linked, you do the same thing with `ARRAY` inside `do_a_call()`. – Martin Deegan Nov 15 '17 at 03:18
  • I don't understand what you mean. [Does this answer your question](https://gist.github.com/2f2573b5864d1c4b353a169b2e26ad69)? The location where the variable is *declared* is important. – Shepmaster Nov 15 '17 at 03:22
  • Ah, I had `#[macro_use(lazy_static)]` instead of `#[macro_use]` and that was saying `INSTANCES` was out of scope. Thanks for the help. – Martin Deegan Nov 15 '17 at 03:29
  • Do you mean something [like this](https://play.integer32.com/?gist=21a9333b8a38ac2ecfe8404f38452a61&version=stable)? That generates **2** errors — the first stating that another macro is missing (`__lazy_static_internal`). If you want to do that, you need to [import all 3 macros, it looks like](https://play.integer32.com/?gist=cf5e197a53ed6c3c3bceb39600af443c&version=stable). – Shepmaster Nov 15 '17 at 03:32
  • Yep, that was the problem. – Martin Deegan Nov 15 '17 at 03:35

0 Answers0