packages feed

thread-utils-context-0.4.1.0: cbits/threadId.cmm

#include "Cmm.h"

// -----------------------------------------------------------------------
// Key encoding
//
// Thread IDs are StgWord32, occupying the low 32 bits of each key slot.
// Bit 32 serves as a "detached" flag: set when the user detaches a
// context, cleared on re-attach.  The probe masks this bit when
// comparing against the target tid and encodes the detached state in
// the return value so the Haskell side never touches the value array
// for detached slots.
//
// Slot hashing uses a Fibonacci/golden-ratio multiplicative hash
// to spread sequential thread IDs across cache lines, avoiding false
// sharing on the key and value arrays.
// -----------------------------------------------------------------------

#define HASH_SALT     0x9E3779B97F4A7C15
#define DETACHED_BIT  0x0000000100000000
#define KEY_MASK      0x00000000FFFFFFFF

// -----------------------------------------------------------------------
// stg_getCurrentThreadId
//
// Returns the current green thread's ID as an Int#.
// Reads StgTSO_id(CurrentTSO) directly, with no myThreadId# box
// allocation, no rts_getThreadId FFI call.
// -----------------------------------------------------------------------

stg_getCurrentThreadId()
{
    return (TO_W_(StgTSO_id(CurrentTSO)));
}


// -----------------------------------------------------------------------
// stg_probeThreadSlot
//
// Fused thread ID retrieval + multiplicative-hash linear probe.
//
// Arguments:
//   P_ keys  : MutableByteArray# holding Int-sized keys per slot
//   W_ mask  : table capacity - 1 (for bitwise AND)
//
// Returns: (Int# tid, Int# slot)
//   slot >= 0   -> entry found and attached at that index
//   slot == -1  -> entry not found
//   slot <= -2  -> entry found but detached; real index = -(slot+2)
// -----------------------------------------------------------------------

stg_probeThreadSlot(P_ keys, W_ mask)
{
    W_ tid, home, slot, key, base, raw_key;

    tid  = TO_W_(StgTSO_id(CurrentTSO));
    home = (tid * HASH_SALT) & mask;
    slot = home;
    base = keys + SIZEOF_StgArrBytes;

  again:
    key = W_[base + WDS(slot)];
    raw_key = key & KEY_MASK;

    if (raw_key == tid) {
        if (key != tid) {
            // Key matches but detached bit is set.
            return (tid, 0 - slot - 2);
        }
        return (tid, slot);
    }

    if (key == 0) {
        return (tid, -1);
    }

    slot = (slot + 1) & mask;
    if (slot != home) {
        goto again;
    }

    return (tid, -1);
}


// -----------------------------------------------------------------------
// stg_probeSlotByKey
//
// Linear probe with an explicit key (not CurrentTSO).
// Used by lookupRaw / updateRaw / adjustOnThread.
//
// Arguments:
//   P_ keys  : MutableByteArray# holding Int-sized keys per slot
//   W_ mask  : table capacity - 1
//   W_ tid   : the raw key to search for (lower 32 bits only)
//
// Returns: Int# slot  (same encoding as stg_probeThreadSlot)
// -----------------------------------------------------------------------

stg_probeSlotByKey(P_ keys, W_ mask, W_ tid)
{
    W_ home, slot, key, base, raw_key;

    home = (tid * HASH_SALT) & mask;
    slot = home;
    base = keys + SIZEOF_StgArrBytes;

  again:
    key = W_[base + WDS(slot)];
    raw_key = key & KEY_MASK;

    if (raw_key == tid) {
        if (key != tid) {
            return (0 - slot - 2);
        }
        return (slot);
    }

    if (key == 0) {
        return (-1);
    }

    slot = (slot + 1) & mask;
    if (slot != home) {
        goto again;
    }

    return (-1);
}