vsync / spinlock / hemlock.h

Hemlock by Dice and Kogan.

Groups: Fair locks

Example:

#include <vsync/spinlock/hemlock.h>
#include <vsync/common/assert.h>
#include <pthread.h>
#include <stdio.h>

#define N            12
#define MAX_THREADS  N
#define EXPECTED_VAL N

hemlock_t g_lock_a = HEMLOCK_INIT();
hemlock_t g_lock_b = HEMLOCK_INIT();

hem_node_t g_nodes[N];

vuint32_t g_x = 0;
vuint32_t g_y = 0;

void *
run(void *args)
{
    vsize_t tid = (vsize_t)args;
    // the same thread context object can be used with multiple instances of
    // hemlock
    hemlock_acquire(&g_lock_a, &g_nodes[tid]);
    hemlock_acquire(&g_lock_b, &g_nodes[tid]);
    g_x++;
    g_y++;
    hemlock_release(&g_lock_b, &g_nodes[tid]);
    hemlock_release(&g_lock_a, &g_nodes[tid]);
    (void)args;
    return NULL;
}

int
main(void)
{
    pthread_t threads[N];

    // use this function as an alternative to HEMLOCK_INIT
    hemlock_init(&g_lock_a);
    hemlock_init(&g_lock_b);

    for (vsize_t i = 0; i < N; i++) {
        pthread_create(&threads[i], NULL, run, (void *)i);
    }

    for (vsize_t i = 0; i < N; i++) {
        pthread_join(threads[i], NULL);
    }

    ASSERT(g_x == EXPECTED_VAL);
    ASSERT(g_x == g_y);
    printf("Final value %u\n", g_x);
    return 0;
}

References:

Dice and Kogan - Hemlock : Compact and Scalable Mutual Exclusion


Macros

Macro Description
HEMLOCK_INIT Initializer of hemlock_t.

Macro HEMLOCK_INIT

HEMLOCK_INIT()

Initializer of hemlock_t.


Functions

Function Description
hemlock_init Initializes the given lock object l.
hemlock_tryacquire Tries to acquire the Hemlock.
hemlock_acquire Acquires the Hemlock.
hemlock_release Releases the Hemlock.
hemlock_has_waiters Returns whether there is a thread waiting to acquire the Hemlock.

Function hemlock_init

static void hemlock_init(hemlock_t *l)

Initializes the given lock object l.

Parameters:

  • l: address of hemlock_t object.

Function hemlock_tryacquire

static int hemlock_tryacquire(hemlock_t *l, hem_node_t *node)

Tries to acquire the Hemlock.

Parameters:

  • l: address of hemlock_t object.
  • node: address of hem_node_t object. Associated with the calling thread/core.

Returns: 1 on success, 0 on failure

Function hemlock_acquire

static void hemlock_acquire(hemlock_t *l, hem_node_t *node)

Acquires the Hemlock.

Parameters:

  • l: address of hemlock_t object.
  • node: address of hem_node_t object. Associated with the calling thread/core.

Function hemlock_release

static void hemlock_release(hemlock_t *l, hem_node_t *node)

Releases the Hemlock.

Parameters:

  • l: address of hemlock_t object.
  • node: address of hem_node_t object. Associated with the calling thread/core.

Function hemlock_has_waiters

static int hemlock_has_waiters(hemlock_t *l, hem_node_t *node)

Returns whether there is a thread waiting to acquire the Hemlock.

This function should only be called by the current owner of the lock.

Parameters:

  • l: address of hemlock_t object.
  • node: address of hem_node_t object. Associated with the calling thread/core.