style: format atomic queue cancellation
CI / lint (pull_request) Failing after 27s
CI / build-and-test (pull_request) Has been skipped
CI / sanitizers (address) (pull_request) Has been skipped
CI / sanitizers (undefined) (pull_request) Has been skipped
CI / fuzz-build (pull_request) Has been skipped
CI / coverage (pull_request) Has been skipped
CI / valgrind (pull_request) Has been skipped

This commit is contained in:
2026-08-09 11:52:51 +02:00
parent d64666d456
commit 1a0a7a19a5
+149 -149
View File
@@ -1,154 +1,154 @@
#include <stdbool.h> #include <stdbool.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <threads.h> #include <threads.h>
#include "queue.h" #include "queue.h"
Queue* queue_create(int capacity, void (*destroyer)(void* item)) { Queue* queue_create(int capacity, void (*destroyer)(void* item)) {
if (capacity <= 0) if (capacity <= 0)
return NULL; return NULL;
Queue* queue = (Queue*)malloc(sizeof(Queue)); Queue* queue = (Queue*)malloc(sizeof(Queue));
if (queue == NULL) { if (queue == NULL) {
perror("ERROR: Could not allocate memory for queue structure"); perror("ERROR: Could not allocate memory for queue structure");
return NULL; return NULL;
} }
queue->items = malloc(capacity * sizeof(void*)); queue->items = malloc(capacity * sizeof(void*));
if (queue->items == NULL) { if (queue->items == NULL) {
free(queue); free(queue);
return NULL; return NULL;
} }
for (int i = 0; i < capacity; ++i) { for (int i = 0; i < capacity; ++i) {
queue->items[i] = NULL; queue->items[i] = NULL;
} }
queue->capacity = capacity; queue->capacity = capacity;
queue->front = 0; queue->front = 0;
queue->rear = 0; queue->rear = 0;
queue->size = 0; queue->size = 0;
queue->item_destroyer = destroyer; queue->item_destroyer = destroyer;
return queue; return queue;
} }
void queue_destroy(Queue* queue) { void queue_destroy(Queue* queue) {
if (queue == NULL) if (queue == NULL)
return; return;
if (queue->item_destroyer != NULL) { if (queue->item_destroyer != NULL) {
for (int i = 0; i < queue->size; ++i) { for (int i = 0; i < queue->size; ++i) {
int index = (queue->front + i) % queue->capacity; int index = (queue->front + i) % queue->capacity;
queue->item_destroyer(queue->items[index]); queue->item_destroyer(queue->items[index]);
} }
} }
free(queue->items); free(queue->items);
free(queue); free(queue);
} }
bool queue_is_empty(const Queue* queue) { bool queue_is_empty(const Queue* queue) {
if (queue == NULL) if (queue == NULL)
return true; return true;
return queue->size == 0; return queue->size == 0;
} }
bool queue_is_full(const Queue* queue) { bool queue_is_full(const Queue* queue) {
if (queue == NULL) if (queue == NULL)
return false; return false;
return queue->size == queue->capacity; return queue->size == queue->capacity;
} }
static bool queue_double_capacity(Queue* queue) { static bool queue_double_capacity(Queue* queue) {
if (queue == NULL) if (queue == NULL)
return false; return false;
if (queue->capacity > INT_MAX / 2) if (queue->capacity > INT_MAX / 2)
return false; return false;
int new_capacity = queue->capacity * 2; int new_capacity = queue->capacity * 2;
if (new_capacity <= 1) if (new_capacity <= 1)
new_capacity = 100; new_capacity = 100;
void** new_items = malloc(new_capacity * sizeof(void*)); void** new_items = malloc(new_capacity * sizeof(void*));
if (new_items == NULL) { if (new_items == NULL) {
perror("ERROR: Could not allocate memory for doubling capacity of queue."); perror("ERROR: Could not allocate memory for doubling capacity of queue.");
return false; return false;
} }
for (int i = 0; i < queue->size; i++) for (int i = 0; i < queue->size; i++)
new_items[i] = queue->items[(i + queue->front) % queue->capacity]; new_items[i] = queue->items[(i + queue->front) % queue->capacity];
free(queue->items); free(queue->items);
queue->items = new_items; queue->items = new_items;
queue->front = 0; queue->front = 0;
queue->rear = queue->size; queue->rear = queue->size;
queue->capacity = new_capacity; queue->capacity = new_capacity;
return true; return true;
} }
bool queue_enqueue(Queue* queue, void* item) { bool queue_enqueue(Queue* queue, void* item) {
if (queue == NULL || item == NULL) if (queue == NULL || item == NULL)
return false; return false;
if (queue_is_full(queue)) { if (queue_is_full(queue)) {
if (!queue_double_capacity(queue)) if (!queue_double_capacity(queue))
return false; return false;
} }
queue->items[queue->rear] = item; queue->items[queue->rear] = item;
queue->rear = (queue->rear + 1) % queue->capacity; queue->rear = (queue->rear + 1) % queue->capacity;
queue->size++; queue->size++;
return true; return true;
} }
bool queue_enqueue_multithreaded(Queue* queue, void* item, mtx_t* mutex, cnd_t* condition_not_empty, bool queue_enqueue_multithreaded(Queue* queue, void* item, mtx_t* mutex, cnd_t* condition_not_empty,
cnd_t* condition_not_full) { cnd_t* condition_not_full) {
mtx_lock(mutex); mtx_lock(mutex);
while (queue_is_full(queue)) while (queue_is_full(queue))
cnd_wait(condition_not_full, mutex); cnd_wait(condition_not_full, mutex);
bool ok = queue_enqueue(queue, item); bool ok = queue_enqueue(queue, item);
cnd_signal(condition_not_empty); cnd_signal(condition_not_empty);
mtx_unlock(mutex); mtx_unlock(mutex);
return ok; return ok;
} }
bool queue_enqueue_multithreaded_cancel(Queue* queue, void* item, mtx_t* mutex, bool queue_enqueue_multithreaded_cancel(Queue* queue, void* item, mtx_t* mutex,
cnd_t* condition_not_empty, cnd_t* condition_not_full, cnd_t* condition_not_empty, cnd_t* condition_not_full,
const atomic_bool* cancelled) { const atomic_bool* cancelled) {
mtx_lock(mutex); mtx_lock(mutex);
while (queue_is_full(queue) && (cancelled == NULL || !atomic_load(cancelled))) while (queue_is_full(queue) && (cancelled == NULL || !atomic_load(cancelled)))
cnd_wait(condition_not_full, mutex); cnd_wait(condition_not_full, mutex);
if (cancelled != NULL && atomic_load(cancelled)) { if (cancelled != NULL && atomic_load(cancelled)) {
mtx_unlock(mutex); mtx_unlock(mutex);
return false; return false;
} }
bool ok = queue_enqueue(queue, item); bool ok = queue_enqueue(queue, item);
cnd_signal(condition_not_empty); cnd_signal(condition_not_empty);
mtx_unlock(mutex); mtx_unlock(mutex);
return ok; return ok;
} }
void* queue_dequeue(Queue* queue) { void* queue_dequeue(Queue* queue) {
if (queue == NULL || queue_is_empty(queue)) { if (queue == NULL || queue_is_empty(queue)) {
perror("ERROR: Could not dequeue from null or empty queue."); perror("ERROR: Could not dequeue from null or empty queue.");
return NULL; return NULL;
} }
void* item = queue->items[queue->front]; void* item = queue->items[queue->front];
queue->items[queue->front] = NULL; queue->items[queue->front] = NULL;
queue->front = (queue->front + 1) % queue->capacity; queue->front = (queue->front + 1) % queue->capacity;
queue->size--; queue->size--;
return item; return item;
} }
void* queue_dequeue_multithreaded(Queue* queue, mtx_t* mutex, cnd_t* condition_not_empty, void* queue_dequeue_multithreaded(Queue* queue, mtx_t* mutex, cnd_t* condition_not_empty,
cnd_t* condition_not_full, const bool* other_thread_done) { cnd_t* condition_not_full, const bool* other_thread_done) {
mtx_lock(mutex); mtx_lock(mutex);
while (queue_is_empty(queue) && !*other_thread_done) while (queue_is_empty(queue) && !*other_thread_done)
cnd_wait(condition_not_empty, mutex); cnd_wait(condition_not_empty, mutex);
if (queue_is_empty(queue) && *other_thread_done) { if (queue_is_empty(queue) && *other_thread_done) {
mtx_unlock(mutex); mtx_unlock(mutex);
return NULL; return NULL;
} }
void* item = queue_dequeue(queue); void* item = queue_dequeue(queue);
cnd_signal(condition_not_full); cnd_signal(condition_not_full);
mtx_unlock(mutex); mtx_unlock(mutex);
return item; return item;
} }