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