PingPong.im

// Actually, this is PingPong for N=2.
// After that it's more of a RoundRobin.

uses thread.createThread, thread.Thread,
     thread.Runnable, thread.sleep, thread.wait,
     synch.createSemaphore, synch.Semaphore,
     io.print, conv.itos, conv.stoi,
     system.exit

class PingPong implements Runnable {
    msg:Message
    s:array[Semaphore]
    id:int

    init(msg_:Message, s_:array[Semaphore], id_:int):PingPong = (
        msg = msg_;
        s = s_;
        id = id_;
        this
    )

    name():string = "T" + itos(id)

    run() = (
        while (true) (
            myS:Semaphore = s[id];
            myS.wait();

            m:string = msg.getMessage();
            i:int = stoi(m, 0);
            j:int = i + 1;
            m = itos(j);
            msg.setMessage(m);

            print(name() + ": " + itos(i) + " -> " + itos(j) + "\N");

            nextS:Semaphore = s[(id+1)%N];
            nextS.signal();

            if (j > 4*N) break;
            sleep(100*(id+1));
        );
    )
}

class Message {
    msg:string
    getMessage():string = msg
    setMessage(newMsg:string) = (msg = newMsg)
}

N:int

main(args:array[string]):int = (

    if (length args < 1) (
        print("Usage: PingPong <N>\N");
        exit(1);
    );

    N = stoi(args[0], 2);
    s:array[Semaphore] = new Semaphore[N](null);

    i:int = 0;
    while (i < N) (
        init:int = (if (i == N-1) 0 else 1);
        s[i] = createSemaphore(init, 1);
        i++;
    );

    msg:Message = new Message;
    msg.setMessage("0");

    t:array[Thread] = new Thread[N](null);

    i = 0;
    while (i < N) (
        t[i] = createThread(new PingPong.init(msg, s, i));
        i++;
    );

    i = 0;
    while (i < N) (
        t[i].start();
        i++;
    );

    i = 0;
    while (i < N) (
        wait(t[i]);
        i++;
    );

    0
)