Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/pthread/em_task_queue.h
6171 views
1
/*
2
* Copyright 2021 The Emscripten Authors. All rights reserved.
3
* Emscripten is available under two separate licenses, the MIT license and the
4
* University of Illinois/NCSA Open Source License. Both these licenses can be
5
* found in the LICENSE file.
6
*/
7
8
#pragma once
9
10
#include <pthread.h>
11
12
#include "proxying_notification_state.h"
13
14
// A task is an arbitrary function combined with some arbitrary state.
15
typedef struct task {
16
void (*func)(void*);
17
void (*cancel)(void*);
18
void* arg;
19
} task;
20
21
// A task queue holding tasks to be processed by a particular thread. The only
22
// "public" field is `notification`. All other fields should be considered
23
// private implementation details.
24
typedef struct em_task_queue {
25
// Flag encoding the state of postMessage notifications for this task queue.
26
// Accessed directly from JS, so must be the first member.
27
_Atomic notification_state notification;
28
// Protects all modifications to mutable `em_task_queue` state.
29
pthread_mutex_t mutex;
30
// The target thread for this em_task_queue. Immutable and accessible without
31
// acquiring the mutex.
32
pthread_t thread;
33
// Recursion guard. Only accessed on the target thread, so there's no need to
34
// hold the lock when accessing it. TODO: We disallow recursive processing
35
// because that's what the old proxying API does, so it is safer to start with
36
// the same behavior. Experiment with relaxing this restriction.
37
int processing;
38
// Ring buffer of tasks of size `capacity`. New tasks are enqueued at
39
// `tail` and dequeued at `head`.
40
task* tasks;
41
int capacity;
42
int head;
43
int tail;
44
// Doubly linked list pointers for the zombie list. See em_task_queue.c for
45
// details.
46
struct em_task_queue* zombie_prev;
47
struct em_task_queue* zombie_next;
48
} em_task_queue;
49
50
em_task_queue* em_task_queue_create(pthread_t thread);
51
52
void em_task_queue_destroy(em_task_queue* queue);
53
54
// Execute tasks until an empty queue is observed. Internally locks the queue.
55
void em_task_queue_execute(em_task_queue* queue);
56
57
// Cancel all tasks in the queue. Internally locks the queue.
58
void em_task_queue_cancel(em_task_queue* queue);
59
60
// Not thread safe.
61
static inline int em_task_queue_is_empty(em_task_queue* queue) {
62
return queue->head == queue->tail;
63
}
64
65
// Not thread safe.
66
static inline int em_task_queue_is_full(em_task_queue* queue) {
67
return queue->head == (queue->tail + 1) % queue->capacity;
68
}
69
70
// Not thread safe. Returns 1 on success and 0 on failure.
71
int em_task_queue_enqueue(em_task_queue* queue, task t);
72
73
// Not thread safe. Assumes the queue is not empty.
74
task em_task_queue_dequeue(em_task_queue* queue);
75
76
// Atomically enqueue the task and schedule the queue to be executed next time
77
// its owning thread returns to its event loop. Returns 1 on success and 0
78
// otherwise. Internally locks the queue.
79
int em_task_queue_send(em_task_queue* queue, task t);
80
81