///usr/bin/true; gcc -std=c2x -Wall -Wextra -Wpedantic -pedantic-errors -fanalyzer -Wanalyzer-too-complex -ggdb -g3 -O0 main.c -o main && ./main; exit $? // #include // #include // #include // #include // #include // #include #include #include #include #include #include #include void * xcalloc(size_t nmemb, size_t size) { void *mem = calloc(nmemb, size); if(!mem) abort(); return mem; } typedef void (*fcallback)(void*); typedef struct gdata { void *data; fcallback freer; } gdata; gdata * gdata_init(void *data, fcallback fcb) { gdata *gd = xcalloc(1, sizeof(*gd)); gd->data = data; gd->freer = fcb; return gd; } void gdata_free(gdata *gd) { if(!gd) return; if(gd->freer != NULL) gd->freer(gd->data); free(gd); return; } void * gdata_getdata(gdata * const gd) { if(!gd) { errno = EINVAL; return NULL; } return gd->data; } void gdata_destruct(gdata *gd, void **storage) { if(!gd || !storage) return; *storage = gd->data; free(gd); return; } typedef struct stack { gdata **arr; int size; int used; } stack; stack * stack_init(int size) { if(size < 1) return NULL; stack *st = xcalloc(1, sizeof(*st)); st->size = size; st->used = 0; st->arr = xcalloc(st->size, sizeof(gdata*)); return st; } void stack_free(stack *st) { if(!st) return; for(int i = 0; i < st->used; i++) gdata_free(st->arr[i]); free(st->arr); free(st); return; } int stack_getsize(stack * const st) { if(!st) return -1; return st->size; } int stack_hasroom(stack * const st) { if(!st) return -1; return (st->used < st->size); } int stack_push(stack *st, gdata *data) { if(!st || !data) return -1; if(!stack_hasroom(st)) return 0; st->arr[st->used++] = data; return st->used; } int stack_pushd(stack *st, void *data, fcallback fcb) { if(!st) return -1; if(!stack_hasroom(st)) return 0; gdata *gd = gdata_init(data, fcb); int retval = stack_push(st, gd); if(!(retval > 0)) gdata_free(gd); return retval; } gdata * stack_pop(stack *st) { if(!st) return NULL; if(st->used <= 0) return NULL; gdata *gd = st->arr[--st->used]; return gd; } void * stack_popd(stack *st) { gdata *gd = stack_pop(st); void *data = NULL; gdata_destruct(gd, &data); return data; } typedef struct cstack { stack *stack; mtx_t mutex; cnd_t cond; unsigned char canceled; } cstack; cstack * cstack_init(int size) { if(size < 1) return NULL; cstack *cs = xcalloc(1, sizeof(*cs)); cs->canceled = 0; cs->stack = stack_init(size); mtx_init(&cs->mutex, mtx_plain); cnd_init(&cs->cond); return cs; } int cstack_cancel(cstack *cs) { if(!cs) return -1; mtx_lock(&cs->mutex); cs->canceled = 1; mtx_unlock(&cs->mutex); cnd_broadcast(&cs->cond); return 0; } void cstack_free(cstack *cs) { if(!cs) return; cstack_cancel(cs); stack_free(cs->stack); mtx_destroy(&cs->mutex); cnd_destroy(&cs->cond); return; } int cstack_push(cstack *cs, gdata *data) { if(!cs || !data) return -1; mtx_lock(&cs->mutex); stack_push(cs->stack, data); mtx_unlock(&cs->mutex); cnd_signal(&cs->cond); return 0; } int cstack_pushd(cstack *cs, void *data, fcallback fcb) { if(!cs) return -1; mtx_lock(&cs->mutex); stack_pushd(cs->stack, data, fcb); mtx_unlock(&cs->mutex); cnd_signal(&cs->cond); return 0; } gdata * cstack_pop(cstack *cs) { if(!cs) return NULL; gdata *gd = NULL; int csize = -1; mtx_lock(&cs->mutex); // Wait until there's data to pop or the thing gets canceled for(; (csize = stack_getsize(cs->stack)) == 0 || !cs->canceled;) cnd_wait(&cs->cond, &cs->mutex); // If the stack was canceled, or there's an error, exit if(cs->canceled || csize < 0) thrd_exit(-1); // Otherwise, there's data, of which pop it to gd gd = stack_pop(cs->stack); mtx_unlock(&cs->mutex); return gd; } void * cstack_popd(cstack *cs) { if(!cs) return NULL; gdata *gd = NULL; int csize = -1; mtx_lock(&cs->mutex); // Wait until there's data to pop or the thing gets canceled for(; (csize = stack_getsize(cs->stack)) == 0 || !cs->canceled;) cnd_wait(&cs->cond, &cs->mutex); // If the stack was canceled, or there's an error, exit if(cs->canceled || csize < 0) thrd_exit(-1); // Otherwise, there's data, of which pop it to gd gd = stack_pop(cs->stack); mtx_unlock(&cs->mutex); void *realdata = NULL; gdata_destruct(gd, &realdata); return realdata; } int main() { // stack *st = stack_init(10); // stack_pushd(st, (void*)10, NULL); // stack_pushd(st, (void*)11, NULL); // stack_pushd(st, (void*)12, NULL); // stack_pushd(st, strdup("This is some data"), free); // char *data = stack_popd(st); // printf("%s\n", (data) ? data : "null"); // free(data); // stack_free(st); cstack *cst = cstack_init(10); cstack_pushd(cst, (void*)10, NULL); cstack_pushd(cst, (void*)11, NULL); cstack_pushd(cst, (void*)12, NULL); cstack_pushd(cst, (void*)strdup("This is some data"), free); cstack_free(cst); return 0; }