/*
    * main.cpp
    * Threading smoke test for MontaukOS.
    * Copyright (c) 2026 Daniel Hammer
    *
    * Spawns two worker threads that increment a shared counter under a
    * userspace mutex, joins them, and reports the result.
*/

#include <montauk/syscall.h>
#include <montauk/thread.h>

using montauk::Mutex;

static constexpr int ITERS_PER_THREAD = 100000;

struct WorkerState {
    Mutex* lock;
    int* counter;
    int delta;
};

static int worker(void* raw) {
    auto* s = (WorkerState*)raw;
    for (int i = 0; i < ITERS_PER_THREAD; i++) {
        s->lock->lock();
        *(s->counter) += s->delta;
        s->lock->unlock();
    }
    return s->delta;
}

static void print_int(int v) {
    char buf[16];
    int n = 0;
    if (v == 0) {
        buf[n++] = '0';
    } else {
        bool neg = v < 0;
        unsigned int u = neg ? (unsigned int)(-(long long)v) : (unsigned int)v;
        char tmp[16]; int t = 0;
        while (u) { tmp[t++] = (char)('0' + (u % 10)); u /= 10; }
        if (neg) buf[n++] = '-';
        while (t) buf[n++] = tmp[--t];
    }
    buf[n] = '\0';
    montauk::print(buf);
}

extern "C" void _start() {
    Mutex lock;
    int counter = 0;

    WorkerState a{&lock, &counter, +1};
    WorkerState b{&lock, &counter, +2};

    int tidA = montauk::thread_spawn(worker, &a);
    int tidB = montauk::thread_spawn(worker, &b);
    if (tidA < 0 || tidB < 0) {
        montauk::print("threadtest: spawn failed\n");
        montauk::exit(1);
    }

    montauk::print("threadtest: spawned tids ");
    print_int(tidA);
    montauk::print(" and ");
    print_int(tidB);
    montauk::print("\n");

    int codeA = -1, codeB = -1;
    if (montauk::thread_join(tidA, &codeA) != 0) {
        montauk::print("threadtest: join A failed\n");
        montauk::exit(2);
    }
    if (montauk::thread_join(tidB, &codeB) != 0) {
        montauk::print("threadtest: join B failed\n");
        montauk::exit(3);
    }

    int expected = ITERS_PER_THREAD * (1 + 2);
    montauk::print("threadtest: counter=");
    print_int(counter);
    montauk::print(" expected=");
    print_int(expected);
    montauk::print(" codes=");
    print_int(codeA);
    montauk::print("/");
    print_int(codeB);
    montauk::print("\n");

    if (counter != expected) {
        montauk::print("threadtest: FAIL (counter mismatch)\n");
        montauk::exit(4);
    }
    if (codeA != 1 || codeB != 2) {
        montauk::print("threadtest: FAIL (exit codes)\n");
        montauk::exit(5);
    }
    montauk::print("threadtest: PASS\n");
    montauk::exit(0);
}
