<commit_before>namespace syscall {

namespace {

enum syscalls_builtins {
    MSG_NONE = 0,
    SYS_RECV = MSG_NONE,
    SYS_MAP,
    SYS_PFAULT,
    SYS_UNMAP,
    SYS_HMOD,
    SYS_NEWPROC, // Not really used, ungood.
    SYS_WRITE = 6,
    // arg0 (dst) = port
    // arg1 = flags (i/o) and data size:
    //  0x10 = write (or with data size)
    //  0x01 = byte
    //  0x02 = word
    //  0x04 = dword
    // arg2 (if applicable) = data for output
    SYS_IO = 7, // Backdoor!
    SYS_GRANT = 8,
    SYS_PULSE = 9,

    MSG_USER = 16,
    MSG_MASK = 0xff,
};

enum msg_kind {
    MSG_KIND_MASK = 0x300,
    MSG_KIND_SEND = 0x000,
    MSG_KIND_CALL = 0x100,
};

u64 portio(u16 port, u8 op, u32 data) {
    log(portio, "portio: port=%x op=%x data=%x\n", port, op, data);
    u32 res = 0;
    switch (op) {
    case 0x01: asm("inb %%dx, %%al" : "=a"(res) : "d"(port)); break;
    case 0x02: asm("inw %%dx, %%ax" : "=a"(res) : "d"(port)); break;
    case 0x04: asm("inl %%dx, %%eax" : "=a"(res) : "d"(port)); break;
    case 0x11: asm("outb %%al, %%dx" :: "a"(data), "d"(port)); break;
    case 0x12: asm("outw %%ax, %%dx" :: "a"(data), "d"(port)); break;
    case 0x14: asm("outl %%eax, %%dx" :: "a"(data), "d"(port)); break;
    }
    if ((op & 0x10) == 0) {
        log(portio, "portio: res=%x\n", res);
    }
    return res;
}

void hmod(Process *p, uintptr_t id, uintptr_t rename, uintptr_t copy) {
    log(hmod, "%s hmod: id=%lx rename=%lx copy=%lx\n", p->name(), id, rename, copy);
    AddressSpace* aspace = p->aspace.get();
    if (auto handle = aspace->find_handle(id)) {
        if (copy) {
            aspace->new_handle(copy, handle->otherspace);
        }
        if (rename) {
            aspace->rename_handle(handle, rename);
        } else {
            aspace->delete_handle(handle);
        }
    }
}

void transfer_set_handle(Process *target, Process *source) {
    auto rcpt = target->regs.rdi;
    auto from = source->regs.rdi;

    auto h = source->find_handle(from);
    if (!rcpt) {
        rcpt = h->other->key();
    } else if (!target->find_handle(rcpt)) {
        if (auto g = h->other) {
            rcpt = g->key();
            assert(g->other == h);
            log(transfer_message, "transfer_set_handle: g=%p, g.id=%lx\n",
                g, rcpt);
        } else {
            // Associate new handle
            g = target->new_handle(rcpt, source->aspace.get());
            g->associate(target->aspace.get(), h);
            assert(g->key() == rcpt);
        }
    } else {
        assert(rcpt == h->other->key());
    }
    log(transfer_message, "transfer_set_handle: rcpt=%lx for %lx from %lx\n",
            rcpt, target->regs.rdi, from);
    target->regs.rdi = rcpt;
}

NORETURN void syscall_return(Process *p, u64 res) {
    getcpu().syscall_return(p, res);
}

NORETURN void transfer_message(Process *target, Process *source) {
    transfer_set_handle(target, source);
    log(transfer_message, "transfer_message %s <- %s\n", target->name(), source->name());

    target->regs.rax = source->regs.rax;
    target->regs.rsi = source->regs.rsi;
    target->regs.rdx = source->regs.rdx;
    target->regs.r8 = source->regs.r8;
    target->regs.r9 = source->regs.r9;
    target->regs.r10 = source->regs.r10;

    target->unset(proc::InRecv);
    target->unset(proc::FastRet);
    source->unset(proc::InSend);
    source->remove_waiter(target);

    Cpu& c = getcpu();
    c.queue(target);
    if (!source->ipc_state()) {
        target->remove_waiter(source);
        c.queue(source);
    }
    c.run();
}

void send_or_block(Process *sender, Handle *h, u64 msg, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) {
    auto other = h->other;
    assert(other);

    sender->regs.rax = msg;
    sender->regs.rdi = h->key();
    sender->regs.rsi = arg1;
    sender->regs.rdx = arg2;
    sender->regs.r10 = arg3;
    sender->regs.r8 = arg4;
    sender->regs.r9 = arg5;

    if (auto p = sender->aspace->pop_recipient(h)) {
        log(ipc, "send_or_block: %s sends to (specific) %s\n", sender->name(), p->name());
        transfer_message(p, sender);
    } else if (auto p = h->otherspace->pop_open_recipient()) {
        log(ipc, "send_or_block: %s sends to %s\n", sender->name(), p->name());
        transfer_message(p, sender);
    } else {
        log(ipc, "send_or_block: no available recipient, %s waits for %s\n", sender->name(), h->otherspace->name());
        sender->wait_for(h->otherspace);<commit_msg>Make sender wait for recipient of IPC call<commit_after>namespace syscall {

namespace {

enum syscalls_builtins {
    MSG_NONE = 0,
    SYS_RECV = MSG_NONE,
    SYS_MAP,
    SYS_PFAULT,
    SYS_UNMAP,
    SYS_HMOD,
    SYS_NEWPROC, // Not really used, ungood.
    SYS_WRITE = 6,
    // arg0 (dst) = port
    // arg1 = flags (i/o) and data size:
    //  0x10 = write (or with data size)
    //  0x01 = byte
    //  0x02 = word
    //  0x04 = dword
    // arg2 (if applicable) = data for output
    SYS_IO = 7, // Backdoor!
    SYS_GRANT = 8,
    SYS_PULSE = 9,

    MSG_USER = 16,
    MSG_MASK = 0xff,
};

enum msg_kind {
    MSG_KIND_MASK = 0x300,
    MSG_KIND_SEND = 0x000,
    MSG_KIND_CALL = 0x100,
};

u64 portio(u16 port, u8 op, u32 data) {
    log(portio, "portio: port=%x op=%x data=%x\n", port, op, data);
    u32 res = 0;
    switch (op) {
    case 0x01: asm("inb %%dx, %%al" : "=a"(res) : "d"(port)); break;
    case 0x02: asm("inw %%dx, %%ax" : "=a"(res) : "d"(port)); break;
    case 0x04: asm("inl %%dx, %%eax" : "=a"(res) : "d"(port)); break;
    case 0x11: asm("outb %%al, %%dx" :: "a"(data), "d"(port)); break;
    case 0x12: asm("outw %%ax, %%dx" :: "a"(data), "d"(port)); break;
    case 0x14: asm("outl %%eax, %%dx" :: "a"(data), "d"(port)); break;
    }
    if ((op & 0x10) == 0) {
        log(portio, "portio: res=%x\n", res);
    }
    return res;
}

void hmod(Process *p, uintptr_t id, uintptr_t rename, uintptr_t copy) {
    log(hmod, "%s hmod: id=%lx rename=%lx copy=%lx\n", p->name(), id, rename, copy);
    AddressSpace* aspace = p->aspace.get();
    if (auto handle = aspace->find_handle(id)) {
        if (copy) {
            aspace->new_handle(copy, handle->otherspace);
        }
        if (rename) {
            aspace->rename_handle(handle, rename);
        } else {
            aspace->delete_handle(handle);
        }
    }
}

void transfer_set_handle(Process *target, Process *source) {
    auto rcpt = target->regs.rdi;
    auto from = source->regs.rdi;

    auto h = source->find_handle(from);
    if (!rcpt) {
        rcpt = h->other->key();
    } else if (!target->find_handle(rcpt)) {
        if (auto g = h->other) {
            rcpt = g->key();
            assert(g->other == h);
            log(transfer_message, "transfer_set_handle: g=%p, g.id=%lx\n",
                g, rcpt);
        } else {
            // Associate new handle
            g = target->new_handle(rcpt, source->aspace.get());
            g->associate(target->aspace.get(), h);
            assert(g->key() == rcpt);
        }
    } else {
        assert(rcpt == h->other->key());
    }
    log(transfer_message, "transfer_set_handle: rcpt=%lx for %lx from %lx\n",
            rcpt, target->regs.rdi, from);
    target->regs.rdi = rcpt;
}

NORETURN void syscall_return(Process *p, u64 res) {
    getcpu().syscall_return(p, res);
}

NORETURN void transfer_message(Process *target, Process *source) {
    transfer_set_handle(target, source);
    log(transfer_message, "transfer_message %s <- %s\n", target->name(), source->name());

    target->regs.rax = source->regs.rax;
    target->regs.rsi = source->regs.rsi;
    target->regs.rdx = source->regs.rdx;
    target->regs.r8 = source->regs.r8;
    target->regs.r9 = source->regs.r9;
    target->regs.r10 = source->regs.r10;

    target->unset(proc::InRecv);
    target->unset(proc::FastRet);
    source->unset(proc::InSend);
    source->remove_waiter(target);

    Cpu& c = getcpu();
    c.queue(target);
    if (!source->ipc_state()) {
        target->remove_waiter(source);
        c.queue(source);
    } else {
        target->add_waiter(source);
    }
    c.run();
}

void send_or_block(Process *sender, Handle *h, u64 msg, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) {
    auto other = h->other;
    assert(other);

    sender->regs.rax = msg;
    sender->regs.rdi = h->key();
    sender->regs.rsi = arg1;
    sender->regs.rdx = arg2;
    sender->regs.r10 = arg3;
    sender->regs.r8 = arg4;
    sender->regs.r9 = arg5;

    if (auto p = sender->aspace->pop_recipient(h)) {
        log(ipc, "send_or_block: %s sends to (specific) %s\n", sender->name(), p->name());
        transfer_message(p, sender);
    } else if (auto p = h->otherspace->pop_open_recipient()) {
        log(ipc, "send_or_block: %s sends to %s\n", sender->name(), p->name());
        transfer_message(p, sender);
    } else {
        log(ipc, "send_or_block: no available recipient, %s waits for %s\n", sender->name(), h->otherspace->name());
        sender->wait_for(h->otherspace);
{'fraction_non_alphanumeric': 0.1801470588235294, 'fraction_numerical': 0.022950089126559714, 'mean_word_length': 2.560888536295121, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 138, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5673980', 'n_tokens_mistral': 3597, 'n_tokens_neox': 3342, 'n_words': 740}