Skip to content

Instantly share code, notes, and snippets.

@plvhx
Created November 1, 2025 04:31
Show Gist options
  • Select an option

  • Save plvhx/dc91b23a3ca49236dbb17724f953bf5c to your computer and use it in GitHub Desktop.

Select an option

Save plvhx/dc91b23a3ca49236dbb17724f953bf5c to your computer and use it in GitHub Desktop.
lock hierarchy with intrusive list for sequentially running thread routine.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NORETURN(x) ((void)(x))
struct llist {
struct llist *next;
struct llist *prev;
};
struct foo {
int data;
struct llist list;
pthread_mutex_t lock;
};
static struct llist lhead = { &(lhead), &(lhead) };
#ifdef __builtin_offsetof
#define offsetof __builtin_offsetof
#else
#define offsetof(t, m) ((size_t)((void *)&((t *)(0))->m - (size_t)(0)))
#endif
#define container_of(p, t, m) ((t *)((void *)(p) - offsetof(t, m)))
#define llist_for_each_tail(lptr, llist) \
for ((lptr) = (llist)->prev; (lptr) != (llist); (lptr) = (lptr)->prev)
static void llist_add(struct llist *list, struct llist *link)
{
link->next = list->next;
link->prev = list;
list->next = link;
return;
}
static void llist_add_tail(struct llist *list, struct llist *link)
{
list->next->prev = link;
link->next = list->next;
link->prev = list;
list->next = link;
return;
}
static struct foo *foo_init(int data)
{
int stat;
struct foo *ret;
ret = calloc(1, sizeof(struct foo));
if (!ret)
return NULL;
stat = pthread_mutex_init(&ret->lock, NULL);
if (stat != 0)
goto __release;
stat = pthread_mutex_lock(&ret->lock);
if (stat != 0)
goto __destroy_lock;
ret->data = data;
stat = pthread_mutex_unlock(&ret->lock);
if (stat != 0)
goto __destroy_lock;
ret->list.prev = &ret->list;
ret->list.next = &ret->list;
return ret;
__destroy_lock:
NORETURN(pthread_mutex_destroy(&ret->lock));
__release:
free(ret);
__fallback:
return NULL;
}
static void foo_add(struct llist *lptr, int data)
{
struct foo *ret;
ret = foo_init(data);
if (!ret)
return;
llist_add_tail(lptr, &ret->list);
return;
}
static void foo_destroy_tail(struct llist *lhead)
{
struct llist *ltmp;
struct llist *lptr = lhead->prev;
while (lptr != lhead) {
ltmp = lptr->prev;
free(container_of(lptr, struct foo, list));
lptr = ltmp;
}
return;
}
static void *insertion_thread(void *arg)
{
int i;
struct llist *lptr = (struct llist *)arg;
for (i = 0; i < 10; i++)
foo_add(lptr, i);
return NULL;
}
static void *printer_thread(void *arg)
{
struct llist *lptr;
struct llist *lhead = (struct llist *)arg;
llist_for_each_tail(lptr, lhead)
printf("%d\n", container_of(lptr, struct foo, list)->data);
return NULL;
}
int main(void)
{
int ret;
pthread_t ta, tb;
ret = pthread_create(
&ta,
NULL,
insertion_thread,
&lhead
);
if (ret != 0)
return -1;
ret = pthread_join(ta, NULL);
if (ret != 0)
return -1;
ret = pthread_create(
&tb,
NULL,
printer_thread,
&lhead
);
if (ret != 0)
return -1;
ret = pthread_join(tb, NULL);
if (ret != 0)
return -1;
foo_destroy_tail(&lhead);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment