Search code examples
cmultithreadingrustrust-tokio

Call Rust DLL function to spawn new thread from C wrapper and return the main thread back to C


I have a use case where C wrapper is loading the Rust DLL. Both C and Rust have infinate loop.

C code

#include "main.h"
#include <stdio.h>
#include "addition.h"
#include <time.h>
#include <unistd.h>

extern void spawn_thread_and_get_back(); // Rust function :
extern void keep_calling_rust_fn(); // Rust function :

int main()
{
    spawn_thread_and_get_back(); // This should spawn thread with infinite loop in rust

    int sleep_seconds = 7;
    
    
    while(1){
      
        printf("Calling rust function);

        keep_calling_rust_fn(); // Call rust function
    }
}

and here is the rust lib code


async fn counter() {
    loop {
        println!("I am getting called by Tokio every 2 seconds");
        // Sleep for 1 second
        sleep(Duration::from_secs(2)).await;
    }
}

#[tokio::main]
async fn runForever() {
    let counterTask = tokio::spawn(
        counter()
    );
    tokio::try_join!(counterTask);

}

use std::thread;

#[no_mangle]
pub unsafe extern "C" fn spawn_thread_and_get_back() {
    let handle = thread::spawn(move || {
        // some work here
        println!("Trying to create new thread for Tokio runtime");
        runForever();

    });
    handle.join();
}

#[no_mangle]
pub unsafe extern "C" fn keep_calling_rust_fn() {
    println!("I am getting called by C wrapper every 7 second");
    someRandomPrintTask();
}


async fn printTask(task_number: u32) {
    println!("Print task {} -", task_number);
}

async fn someRandomPrintTask() {
    let printTask = tokio::spawn(
        printTask(10)
    );
    tokio::try_join!(printTask);
}

The issue I am facing is once I call the spawn_thread_and_get_back() from C and never get the thread back to execute while loop in C

I would like to call the rust DLL from C and spawn seperate thread for rust. And the idea is the caller thread from C will get free once it initializes the rust forever loop thread.


Solution

  • Thanks everyone, After discussing in the comments above, here is the working answer. We just need to change Rust code

    
    async fn counter() {
        loop {
            println!("I am getting called by Tokio every 2 seconds");
            // Sleep for 1 second
            sleep(Duration::from_secs(2)).await;
        }
    }
    
    #[tokio::main]
    async fn runForever() {
        let counterTask = tokio::spawn(
            counter()
        );
        tokio::try_join!(counterTask);
    
    }
    
    use std::thread;
    
    #[no_mangle]
    pub unsafe extern "C" fn spawn_thread_and_get_back() {
        let handle = thread::spawn(move || {
            // some work here
            println!("Trying to create new thread for Tokio runtime");
            runForever();
    
        });
        
    
       `handle.join();` *** Update - Removed this as it was blocking the main thread as it was waiting for handle to finish ***
    
    }
    
    #[no_mangle]
    pub unsafe extern "C" fn keep_calling_rust_fn() {
        println!("I am getting called by C wrapper every 7 second");
        someRandomPrintTask();
    }
    
    
    async fn printTask(task_number: u32) {
        println!("Print task {} -", task_number);
    }
    
    #[tokio::main]  *** Update - Added the decorater here ***
    async fn someRandomPrintTask() {
        let printTask = tokio::spawn(
            printTask(10)
        );
        tokio::try_join!(printTask);
    }