Path: blob/main/system/lib/pthread/em_task_queue.h
6171 views
/*1* Copyright 2021 The Emscripten Authors. All rights reserved.2* Emscripten is available under two separate licenses, the MIT license and the3* University of Illinois/NCSA Open Source License. Both these licenses can be4* found in the LICENSE file.5*/67#pragma once89#include <pthread.h>1011#include "proxying_notification_state.h"1213// A task is an arbitrary function combined with some arbitrary state.14typedef struct task {15void (*func)(void*);16void (*cancel)(void*);17void* arg;18} task;1920// A task queue holding tasks to be processed by a particular thread. The only21// "public" field is `notification`. All other fields should be considered22// private implementation details.23typedef struct em_task_queue {24// Flag encoding the state of postMessage notifications for this task queue.25// Accessed directly from JS, so must be the first member.26_Atomic notification_state notification;27// Protects all modifications to mutable `em_task_queue` state.28pthread_mutex_t mutex;29// The target thread for this em_task_queue. Immutable and accessible without30// acquiring the mutex.31pthread_t thread;32// Recursion guard. Only accessed on the target thread, so there's no need to33// hold the lock when accessing it. TODO: We disallow recursive processing34// because that's what the old proxying API does, so it is safer to start with35// the same behavior. Experiment with relaxing this restriction.36int processing;37// Ring buffer of tasks of size `capacity`. New tasks are enqueued at38// `tail` and dequeued at `head`.39task* tasks;40int capacity;41int head;42int tail;43// Doubly linked list pointers for the zombie list. See em_task_queue.c for44// details.45struct em_task_queue* zombie_prev;46struct em_task_queue* zombie_next;47} em_task_queue;4849em_task_queue* em_task_queue_create(pthread_t thread);5051void em_task_queue_destroy(em_task_queue* queue);5253// Execute tasks until an empty queue is observed. Internally locks the queue.54void em_task_queue_execute(em_task_queue* queue);5556// Cancel all tasks in the queue. Internally locks the queue.57void em_task_queue_cancel(em_task_queue* queue);5859// Not thread safe.60static inline int em_task_queue_is_empty(em_task_queue* queue) {61return queue->head == queue->tail;62}6364// Not thread safe.65static inline int em_task_queue_is_full(em_task_queue* queue) {66return queue->head == (queue->tail + 1) % queue->capacity;67}6869// Not thread safe. Returns 1 on success and 0 on failure.70int em_task_queue_enqueue(em_task_queue* queue, task t);7172// Not thread safe. Assumes the queue is not empty.73task em_task_queue_dequeue(em_task_queue* queue);7475// Atomically enqueue the task and schedule the queue to be executed next time76// its owning thread returns to its event loop. Returns 1 on success and 077// otherwise. Internally locks the queue.78int em_task_queue_send(em_task_queue* queue, task t);798081