Okay so I got myself a a quick-and-dirty interim quick fix that works... I 
noticed I could just compile the C example into Nim and run it, getting a 
`runRealtime` proc that I can just feed a callback to. Primitive! But does work!

I found you can use proper Nim threads for everything that isn't realtime. In 
my code for now communication is done via global variable flags and locking 
just means resources are only used by one thread or the other.
    
    
    // rt.c
    /*
     * Quick-and-dirty Nim realtime scheduling for Linux
     *
     * Based on the:
     *
     * POSIX Real Time Example
     * using a single pthread as RT thread
     */
    
    #include <limits.h>
    #include <pthread.h>
    #include <sched.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    
    int run_realtime_thread(void *(*tf) ())
    {
            struct sched_param param;
            pthread_attr_t attr;
            pthread_t thread;
            int ret;
            
            /* Lock memory */
            if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
                    printf("mlockall failed: %m\n");
                    exit(-2);
            }
            
            /* Initialize pthread attributes (default values) */
            ret = pthread_attr_init(&attr);
            if (ret) {
                    printf("init pthread attributes failed\n");
                    goto out;
            }
            
            /* Set a specific stack size  */
            ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
            if (ret) {
                printf("pthread setstacksize failed\n");
                goto out;
            }
            
            /* Set scheduler policy and priority of pthread */
            ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
            if (ret) {
                    printf("pthread setschedpolicy failed\n");
                    goto out;
            }
            param.sched_priority = 80;
            ret = pthread_attr_setschedparam(&attr, &param);
            if (ret) {
                    printf("pthread setschedparam failed\n");
                    goto out;
            }
            /* Use scheduling parameters of attr */
            ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
            if (ret) {
                    printf("pthread setinheritsched failed\n");
                    goto out;
            }
            
            /* Create a pthread with specified attributes */
            ret = pthread_create(&thread, &attr, *tf, NULL);
            if (ret) {
                    printf("create pthread failed\n");
                    goto out;
            }
    
    out:
            ret = pthread_join(thread, NULL);
            if (ret)
                    printf("join pthread failed: %m\n");
            
            
            return ret;
    }
    
    
    Run
    
    
    # rt.nim
    import posix
    
    {.compile: "rt.c".}
    
    proc runRealtime*(p: proc () {.cdecl.})
      {.importc: "run_realtime_thread".}
    
    # microsecond sleep (max 1s for now)
    proc nod*(ns: int) =
      var a, b: Timespec
      a.tv_sec = Time(0)
      a.tv_nsec = ns
      discard nanosleep(a, hb)
    
    
    Run
    
    
    # main.nim
    
    # realtime thread
    proc rt() {.cdecl.} =
      while true:
        nod(500_000_000)  # whoo-hoo precise ns sleep
    
    # main thread, non-realtime
    var mainThread = Thread[void]
    proc main {.thread.} =
      while true:
            sleep 1000
    
    createThread(mainThread, main)
    
    runRealtime(rt)
    
    
    
    Run

Reply via email to