Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> I would like to build a rich "process api" that can fork, merge, pause, yield, yield until, drop while, synchronize, wait (latch), react according to events. I feel every distributed systems builds this again and again.

Years ago I attempted to build an experimental language with first-class resumable functions. Every function can be invoked by the caller through a special reference type called "quaint". The caller can resume or stop the execution of the function either after reaching a timeout, or after passing a "wait label":

https://github.com/bbu/quaint-lang

A typical CPU-intensive example where preemption is done by the caller after a certain timeout:

    entry
    {
        fibq: quaint(u32) = ~fibonacci(32 as u32);

        ps("At start: "), pu8(fibq@start), pnl();
        iter: u32 = 0:u32;

        do {
            wait fibq for 1000 msec;
            ps("Iteration "), pu32(iter++), pnl();
        } while !fibq@end;

        ps("At end: "), pu8(fibq@end), pnl();
        const value: u32 = *fibq;
        ps("Reaped value: "), pu32(value), pnl();
    }

    fibonacci(number: u32): u32
    {
        if number == 0:u32 || number == 1:u32 {
            return number;
        } else {
            return fibonacci(number - 1:u32) + fibonacci(number - 2:u32);
        }
    }
An example that uses "wait labels" to suspend execution of the callee at certain points:

    entry
    {
        q: quaint(u64) = ~pointless_function();

        wait q until pointless_function::label_a;
        ps("At label_a: "), pu8(q@pointless_function::label_a), pnl();

        wait q until pointless_function::label_b;
        ps("At label_b: "), pu8(q@pointless_function::label_b), pnl();

        wait q until pointless_function::label_c;
        ps("At label_c: "), pu8(q@pointless_function::label_c), pnl();

        wait q;
        ps("At end: "), pu8(q@end), pnl();

        ps("Result: "), pu64(*q), pnl();
    }

    pointless_function: u64
    {
        i: u64 = 0 as u64;

        while ++i < 1000000:u64 {
            x: vptr = malloc(1024:usize);
            free(x);

            if i == 300000:u64 {
                [label_a]
            } elif i == 600000:u64 {
                [label_b]
            } elif i == 900000:u64 {
                [label_c]
            }
        }

        return i;
    }


I really like this.

Thank you for your comment and sharing.

I have a lightweight 1:M:N runtime (1 scheduler thread, M kernel threads, N lightweight threads) which preempts by setting hot loops to the limit.

https://github.com/samsquire/preemptible-thread (Rust, Java and C)

How do you preempt code that is running?

Would you like to talk more about your idea?


> How do you preempt code that is running?

It runs in its own VM with custom instructions. The "wait" statement corresponds to a special instruction that is able to switch to a separate execution context and restore the parent context when necessary.

To implement this in native code, some kind of runtime support would be needed. Perhaps a dedicated thread that is able to stop/resume the main thread, changing the contents of the stack and the registers.


Ha. Amazing! Someone actually implemented a variant of COME FROM of C-INTERCAL infamy in another language.

And moreover made it a reasonable and readable variant!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: