Created
November 1, 2025 04:31
-
-
Save plvhx/dc91b23a3ca49236dbb17724f953bf5c to your computer and use it in GitHub Desktop.
lock hierarchy with intrusive list for sequentially running thread routine.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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