1*61145dc2SMartin Matuska // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only
2c03c5b1cSMartin Matuska /*
3c03c5b1cSMartin Matuska * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
4c03c5b1cSMartin Matuska * All rights reserved.
5c03c5b1cSMartin Matuska *
6c03c5b1cSMartin Matuska * This source code is licensed under both the BSD-style license (found in the
7c03c5b1cSMartin Matuska * LICENSE file in the root directory of this source tree) and the GPLv2 (found
8c03c5b1cSMartin Matuska * in the COPYING file in the root directory of this source tree).
9c03c5b1cSMartin Matuska * You may select, at your option, one of the above-listed licenses.
10c03c5b1cSMartin Matuska */
11c03c5b1cSMartin Matuska
12c03c5b1cSMartin Matuska
13c03c5b1cSMartin Matuska /* ====== Dependencies ======= */
14c03c5b1cSMartin Matuska #include <stddef.h> /* size_t */
15c03c5b1cSMartin Matuska #include "debug.h" /* assert */
16c03c5b1cSMartin Matuska #include "zstd_internal.h" /* ZSTD_malloc, ZSTD_free */
17c03c5b1cSMartin Matuska #include "pool.h"
18c03c5b1cSMartin Matuska
19c03c5b1cSMartin Matuska /* ====== Compiler specifics ====== */
20c03c5b1cSMartin Matuska #if defined(_MSC_VER)
21c03c5b1cSMartin Matuska # pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
22c03c5b1cSMartin Matuska #endif
23c03c5b1cSMartin Matuska
24c03c5b1cSMartin Matuska
25c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
26c03c5b1cSMartin Matuska
27c03c5b1cSMartin Matuska #include "threading.h" /* pthread adaptation */
28c03c5b1cSMartin Matuska
29c03c5b1cSMartin Matuska /* A job is a function and an opaque argument */
30c03c5b1cSMartin Matuska typedef struct POOL_job_s {
31c03c5b1cSMartin Matuska POOL_function function;
32c03c5b1cSMartin Matuska void *opaque;
33c03c5b1cSMartin Matuska } POOL_job;
34c03c5b1cSMartin Matuska
35c03c5b1cSMartin Matuska struct POOL_ctx_s {
36c03c5b1cSMartin Matuska ZSTD_customMem customMem;
37c03c5b1cSMartin Matuska /* Keep track of the threads */
38c03c5b1cSMartin Matuska ZSTD_pthread_t* threads;
39c03c5b1cSMartin Matuska size_t threadCapacity;
40c03c5b1cSMartin Matuska size_t threadLimit;
41c03c5b1cSMartin Matuska
42c03c5b1cSMartin Matuska /* The queue is a circular buffer */
43c03c5b1cSMartin Matuska POOL_job *queue;
44c03c5b1cSMartin Matuska size_t queueHead;
45c03c5b1cSMartin Matuska size_t queueTail;
46c03c5b1cSMartin Matuska size_t queueSize;
47c03c5b1cSMartin Matuska
48c03c5b1cSMartin Matuska /* The number of threads working on jobs */
49c03c5b1cSMartin Matuska size_t numThreadsBusy;
50c03c5b1cSMartin Matuska /* Indicates if the queue is empty */
51c03c5b1cSMartin Matuska int queueEmpty;
52c03c5b1cSMartin Matuska
53c03c5b1cSMartin Matuska /* The mutex protects the queue */
54c03c5b1cSMartin Matuska ZSTD_pthread_mutex_t queueMutex;
55c03c5b1cSMartin Matuska /* Condition variable for pushers to wait on when the queue is full */
56c03c5b1cSMartin Matuska ZSTD_pthread_cond_t queuePushCond;
57c03c5b1cSMartin Matuska /* Condition variables for poppers to wait on when the queue is empty */
58c03c5b1cSMartin Matuska ZSTD_pthread_cond_t queuePopCond;
59c03c5b1cSMartin Matuska /* Indicates if the queue is shutting down */
60c03c5b1cSMartin Matuska int shutdown;
61c03c5b1cSMartin Matuska };
62c03c5b1cSMartin Matuska
63c03c5b1cSMartin Matuska /* POOL_thread() :
64c03c5b1cSMartin Matuska * Work thread for the thread pool.
65c03c5b1cSMartin Matuska * Waits for jobs and executes them.
66c03c5b1cSMartin Matuska * @returns : NULL on failure else non-null.
67c03c5b1cSMartin Matuska */
POOL_thread(void * opaque)68c03c5b1cSMartin Matuska static void* POOL_thread(void* opaque) {
69c03c5b1cSMartin Matuska POOL_ctx* const ctx = (POOL_ctx*)opaque;
70c03c5b1cSMartin Matuska if (!ctx) { return NULL; }
71c03c5b1cSMartin Matuska for (;;) {
72c03c5b1cSMartin Matuska /* Lock the mutex and wait for a non-empty queue or until shutdown */
73c03c5b1cSMartin Matuska ZSTD_pthread_mutex_lock(&ctx->queueMutex);
74c03c5b1cSMartin Matuska
75c03c5b1cSMartin Matuska while ( ctx->queueEmpty
76c03c5b1cSMartin Matuska || (ctx->numThreadsBusy >= ctx->threadLimit) ) {
77c03c5b1cSMartin Matuska if (ctx->shutdown) {
78c03c5b1cSMartin Matuska /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
79c03c5b1cSMartin Matuska * a few threads will be shutdown while !queueEmpty,
80c03c5b1cSMartin Matuska * but enough threads will remain active to finish the queue */
81c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
82c03c5b1cSMartin Matuska return opaque;
83c03c5b1cSMartin Matuska }
84c03c5b1cSMartin Matuska ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
85c03c5b1cSMartin Matuska }
86c03c5b1cSMartin Matuska /* Pop a job off the queue */
87c03c5b1cSMartin Matuska { POOL_job const job = ctx->queue[ctx->queueHead];
88c03c5b1cSMartin Matuska ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
89c03c5b1cSMartin Matuska ctx->numThreadsBusy++;
90c03c5b1cSMartin Matuska ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
91c03c5b1cSMartin Matuska /* Unlock the mutex, signal a pusher, and run the job */
92c03c5b1cSMartin Matuska ZSTD_pthread_cond_signal(&ctx->queuePushCond);
93c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
94c03c5b1cSMartin Matuska
95c03c5b1cSMartin Matuska job.function(job.opaque);
96c03c5b1cSMartin Matuska
97c03c5b1cSMartin Matuska /* If the intended queue size was 0, signal after finishing job */
98c03c5b1cSMartin Matuska ZSTD_pthread_mutex_lock(&ctx->queueMutex);
99c03c5b1cSMartin Matuska ctx->numThreadsBusy--;
100c03c5b1cSMartin Matuska if (ctx->queueSize == 1) {
101c03c5b1cSMartin Matuska ZSTD_pthread_cond_signal(&ctx->queuePushCond);
102c03c5b1cSMartin Matuska }
103c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
104c03c5b1cSMartin Matuska }
105c03c5b1cSMartin Matuska } /* for (;;) */
106c03c5b1cSMartin Matuska assert(0); /* Unreachable */
107c03c5b1cSMartin Matuska }
108c03c5b1cSMartin Matuska
POOL_create(size_t numThreads,size_t queueSize)109c03c5b1cSMartin Matuska POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
110c03c5b1cSMartin Matuska return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
111c03c5b1cSMartin Matuska }
112c03c5b1cSMartin Matuska
POOL_create_advanced(size_t numThreads,size_t queueSize,ZSTD_customMem customMem)113c03c5b1cSMartin Matuska POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
114c03c5b1cSMartin Matuska ZSTD_customMem customMem) {
115c03c5b1cSMartin Matuska POOL_ctx* ctx;
116c03c5b1cSMartin Matuska /* Check parameters */
117c03c5b1cSMartin Matuska if (!numThreads) { return NULL; }
118c03c5b1cSMartin Matuska /* Allocate the context and zero initialize */
119c03c5b1cSMartin Matuska ctx = (POOL_ctx*)ZSTD_calloc(sizeof(POOL_ctx), customMem);
120c03c5b1cSMartin Matuska if (!ctx) { return NULL; }
121c03c5b1cSMartin Matuska /* Initialize the job queue.
122c03c5b1cSMartin Matuska * It needs one extra space since one space is wasted to differentiate
123c03c5b1cSMartin Matuska * empty and full queues.
124c03c5b1cSMartin Matuska */
125c03c5b1cSMartin Matuska ctx->queueSize = queueSize + 1;
126c03c5b1cSMartin Matuska ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem);
127c03c5b1cSMartin Matuska ctx->queueHead = 0;
128c03c5b1cSMartin Matuska ctx->queueTail = 0;
129c03c5b1cSMartin Matuska ctx->numThreadsBusy = 0;
130c03c5b1cSMartin Matuska ctx->queueEmpty = 1;
131c03c5b1cSMartin Matuska {
132c03c5b1cSMartin Matuska int error = 0;
133c03c5b1cSMartin Matuska error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
134c03c5b1cSMartin Matuska error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
135c03c5b1cSMartin Matuska error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
136c03c5b1cSMartin Matuska if (error) { POOL_free(ctx); return NULL; }
137c03c5b1cSMartin Matuska }
138c03c5b1cSMartin Matuska ctx->shutdown = 0;
139c03c5b1cSMartin Matuska /* Allocate space for the thread handles */
140c03c5b1cSMartin Matuska ctx->threads = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
141c03c5b1cSMartin Matuska ctx->threadCapacity = 0;
142c03c5b1cSMartin Matuska ctx->customMem = customMem;
143c03c5b1cSMartin Matuska /* Check for errors */
144c03c5b1cSMartin Matuska if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
145c03c5b1cSMartin Matuska /* Initialize the threads */
146c03c5b1cSMartin Matuska { size_t i;
147c03c5b1cSMartin Matuska for (i = 0; i < numThreads; ++i) {
148c03c5b1cSMartin Matuska if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
149c03c5b1cSMartin Matuska ctx->threadCapacity = i;
150c03c5b1cSMartin Matuska POOL_free(ctx);
151c03c5b1cSMartin Matuska return NULL;
152c03c5b1cSMartin Matuska } }
153c03c5b1cSMartin Matuska ctx->threadCapacity = numThreads;
154c03c5b1cSMartin Matuska ctx->threadLimit = numThreads;
155c03c5b1cSMartin Matuska }
156c03c5b1cSMartin Matuska return ctx;
157c03c5b1cSMartin Matuska }
158c03c5b1cSMartin Matuska
159c03c5b1cSMartin Matuska /*! POOL_join() :
160c03c5b1cSMartin Matuska Shutdown the queue, wake any sleeping threads, and join all of the threads.
161c03c5b1cSMartin Matuska */
POOL_join(POOL_ctx * ctx)162c03c5b1cSMartin Matuska static void POOL_join(POOL_ctx* ctx) {
163c03c5b1cSMartin Matuska /* Shut down the queue */
164c03c5b1cSMartin Matuska ZSTD_pthread_mutex_lock(&ctx->queueMutex);
165c03c5b1cSMartin Matuska ctx->shutdown = 1;
166c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
167c03c5b1cSMartin Matuska /* Wake up sleeping threads */
168c03c5b1cSMartin Matuska ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
169c03c5b1cSMartin Matuska ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
170c03c5b1cSMartin Matuska /* Join all of the threads */
171c03c5b1cSMartin Matuska { size_t i;
172c03c5b1cSMartin Matuska for (i = 0; i < ctx->threadCapacity; ++i) {
173c03c5b1cSMartin Matuska ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */
174c03c5b1cSMartin Matuska } }
175c03c5b1cSMartin Matuska }
176c03c5b1cSMartin Matuska
POOL_free(POOL_ctx * ctx)177c03c5b1cSMartin Matuska void POOL_free(POOL_ctx *ctx) {
178c03c5b1cSMartin Matuska if (!ctx) { return; }
179c03c5b1cSMartin Matuska POOL_join(ctx);
180c03c5b1cSMartin Matuska ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
181c03c5b1cSMartin Matuska ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
182c03c5b1cSMartin Matuska ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
183c03c5b1cSMartin Matuska ZSTD_free(ctx->queue, ctx->customMem);
184c03c5b1cSMartin Matuska ZSTD_free(ctx->threads, ctx->customMem);
185c03c5b1cSMartin Matuska ZSTD_free(ctx, ctx->customMem);
186c03c5b1cSMartin Matuska }
187c03c5b1cSMartin Matuska
188c03c5b1cSMartin Matuska
189c03c5b1cSMartin Matuska
POOL_sizeof(POOL_ctx * ctx)190c03c5b1cSMartin Matuska size_t POOL_sizeof(POOL_ctx *ctx) {
191c03c5b1cSMartin Matuska if (ctx==NULL) return 0; /* supports sizeof NULL */
192c03c5b1cSMartin Matuska return sizeof(*ctx)
193c03c5b1cSMartin Matuska + ctx->queueSize * sizeof(POOL_job)
194c03c5b1cSMartin Matuska + ctx->threadCapacity * sizeof(ZSTD_pthread_t);
195c03c5b1cSMartin Matuska }
196c03c5b1cSMartin Matuska
197c03c5b1cSMartin Matuska
198c03c5b1cSMartin Matuska /* @return : 0 on success, 1 on error */
POOL_resize_internal(POOL_ctx * ctx,size_t numThreads)199c03c5b1cSMartin Matuska static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
200c03c5b1cSMartin Matuska {
201c03c5b1cSMartin Matuska if (numThreads <= ctx->threadCapacity) {
202c03c5b1cSMartin Matuska if (!numThreads) return 1;
203c03c5b1cSMartin Matuska ctx->threadLimit = numThreads;
204c03c5b1cSMartin Matuska return 0;
205c03c5b1cSMartin Matuska }
206c03c5b1cSMartin Matuska /* numThreads > threadCapacity */
207c03c5b1cSMartin Matuska { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_malloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
208c03c5b1cSMartin Matuska if (!threadPool) return 1;
209c03c5b1cSMartin Matuska /* replace existing thread pool */
210c03c5b1cSMartin Matuska memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
211c03c5b1cSMartin Matuska ZSTD_free(ctx->threads, ctx->customMem);
212c03c5b1cSMartin Matuska ctx->threads = threadPool;
213c03c5b1cSMartin Matuska /* Initialize additional threads */
214c03c5b1cSMartin Matuska { size_t threadId;
215c03c5b1cSMartin Matuska for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
216c03c5b1cSMartin Matuska if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
217c03c5b1cSMartin Matuska ctx->threadCapacity = threadId;
218c03c5b1cSMartin Matuska return 1;
219c03c5b1cSMartin Matuska } }
220c03c5b1cSMartin Matuska } }
221c03c5b1cSMartin Matuska /* successfully expanded */
222c03c5b1cSMartin Matuska ctx->threadCapacity = numThreads;
223c03c5b1cSMartin Matuska ctx->threadLimit = numThreads;
224c03c5b1cSMartin Matuska return 0;
225c03c5b1cSMartin Matuska }
226c03c5b1cSMartin Matuska
227c03c5b1cSMartin Matuska /* @return : 0 on success, 1 on error */
POOL_resize(POOL_ctx * ctx,size_t numThreads)228c03c5b1cSMartin Matuska int POOL_resize(POOL_ctx* ctx, size_t numThreads)
229c03c5b1cSMartin Matuska {
230c03c5b1cSMartin Matuska int result;
231c03c5b1cSMartin Matuska if (ctx==NULL) return 1;
232c03c5b1cSMartin Matuska ZSTD_pthread_mutex_lock(&ctx->queueMutex);
233c03c5b1cSMartin Matuska result = POOL_resize_internal(ctx, numThreads);
234c03c5b1cSMartin Matuska ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
235c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
236c03c5b1cSMartin Matuska return result;
237c03c5b1cSMartin Matuska }
238c03c5b1cSMartin Matuska
239c03c5b1cSMartin Matuska /**
240c03c5b1cSMartin Matuska * Returns 1 if the queue is full and 0 otherwise.
241c03c5b1cSMartin Matuska *
242c03c5b1cSMartin Matuska * When queueSize is 1 (pool was created with an intended queueSize of 0),
243c03c5b1cSMartin Matuska * then a queue is empty if there is a thread free _and_ no job is waiting.
244c03c5b1cSMartin Matuska */
isQueueFull(POOL_ctx const * ctx)245c03c5b1cSMartin Matuska static int isQueueFull(POOL_ctx const* ctx) {
246c03c5b1cSMartin Matuska if (ctx->queueSize > 1) {
247c03c5b1cSMartin Matuska return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
248c03c5b1cSMartin Matuska } else {
249c03c5b1cSMartin Matuska return (ctx->numThreadsBusy == ctx->threadLimit) ||
250c03c5b1cSMartin Matuska !ctx->queueEmpty;
251c03c5b1cSMartin Matuska }
252c03c5b1cSMartin Matuska }
253c03c5b1cSMartin Matuska
254c03c5b1cSMartin Matuska
POOL_add_internal(POOL_ctx * ctx,POOL_function function,void * opaque)255c03c5b1cSMartin Matuska static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
256c03c5b1cSMartin Matuska {
257c03c5b1cSMartin Matuska POOL_job const job = {function, opaque};
258c03c5b1cSMartin Matuska assert(ctx != NULL);
259c03c5b1cSMartin Matuska if (ctx->shutdown) return;
260c03c5b1cSMartin Matuska
261c03c5b1cSMartin Matuska ctx->queueEmpty = 0;
262c03c5b1cSMartin Matuska ctx->queue[ctx->queueTail] = job;
263c03c5b1cSMartin Matuska ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
264c03c5b1cSMartin Matuska ZSTD_pthread_cond_signal(&ctx->queuePopCond);
265c03c5b1cSMartin Matuska }
266c03c5b1cSMartin Matuska
POOL_add(POOL_ctx * ctx,POOL_function function,void * opaque)267c03c5b1cSMartin Matuska void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
268c03c5b1cSMartin Matuska {
269c03c5b1cSMartin Matuska assert(ctx != NULL);
270c03c5b1cSMartin Matuska ZSTD_pthread_mutex_lock(&ctx->queueMutex);
271c03c5b1cSMartin Matuska /* Wait until there is space in the queue for the new job */
272c03c5b1cSMartin Matuska while (isQueueFull(ctx) && (!ctx->shutdown)) {
273c03c5b1cSMartin Matuska ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
274c03c5b1cSMartin Matuska }
275c03c5b1cSMartin Matuska POOL_add_internal(ctx, function, opaque);
276c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
277c03c5b1cSMartin Matuska }
278c03c5b1cSMartin Matuska
279c03c5b1cSMartin Matuska
POOL_tryAdd(POOL_ctx * ctx,POOL_function function,void * opaque)280c03c5b1cSMartin Matuska int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
281c03c5b1cSMartin Matuska {
282c03c5b1cSMartin Matuska assert(ctx != NULL);
283c03c5b1cSMartin Matuska ZSTD_pthread_mutex_lock(&ctx->queueMutex);
284c03c5b1cSMartin Matuska if (isQueueFull(ctx)) {
285c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
286c03c5b1cSMartin Matuska return 0;
287c03c5b1cSMartin Matuska }
288c03c5b1cSMartin Matuska POOL_add_internal(ctx, function, opaque);
289c03c5b1cSMartin Matuska ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
290c03c5b1cSMartin Matuska return 1;
291c03c5b1cSMartin Matuska }
292c03c5b1cSMartin Matuska
293c03c5b1cSMartin Matuska
294c03c5b1cSMartin Matuska #else /* ZSTD_MULTITHREAD not defined */
295c03c5b1cSMartin Matuska
296c03c5b1cSMartin Matuska /* ========================== */
297c03c5b1cSMartin Matuska /* No multi-threading support */
298c03c5b1cSMartin Matuska /* ========================== */
299c03c5b1cSMartin Matuska
300c03c5b1cSMartin Matuska
301c03c5b1cSMartin Matuska /* We don't need any data, but if it is empty, malloc() might return NULL. */
302c03c5b1cSMartin Matuska struct POOL_ctx_s {
303c03c5b1cSMartin Matuska int dummy;
304c03c5b1cSMartin Matuska };
305c03c5b1cSMartin Matuska static POOL_ctx g_ctx;
306c03c5b1cSMartin Matuska
POOL_create(size_t numThreads,size_t queueSize)307c03c5b1cSMartin Matuska POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
308c03c5b1cSMartin Matuska return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
309c03c5b1cSMartin Matuska }
310c03c5b1cSMartin Matuska
POOL_create_advanced(size_t numThreads,size_t queueSize,ZSTD_customMem customMem)311c03c5b1cSMartin Matuska POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) {
312c03c5b1cSMartin Matuska (void)numThreads;
313c03c5b1cSMartin Matuska (void)queueSize;
314c03c5b1cSMartin Matuska (void)customMem;
315c03c5b1cSMartin Matuska return &g_ctx;
316c03c5b1cSMartin Matuska }
317c03c5b1cSMartin Matuska
POOL_free(POOL_ctx * ctx)318c03c5b1cSMartin Matuska void POOL_free(POOL_ctx* ctx) {
319c03c5b1cSMartin Matuska assert(!ctx || ctx == &g_ctx);
320c03c5b1cSMartin Matuska (void)ctx;
321c03c5b1cSMartin Matuska }
322c03c5b1cSMartin Matuska
POOL_resize(POOL_ctx * ctx,size_t numThreads)323c03c5b1cSMartin Matuska int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
324c03c5b1cSMartin Matuska (void)ctx; (void)numThreads;
325c03c5b1cSMartin Matuska return 0;
326c03c5b1cSMartin Matuska }
327c03c5b1cSMartin Matuska
POOL_add(POOL_ctx * ctx,POOL_function function,void * opaque)328c03c5b1cSMartin Matuska void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
329c03c5b1cSMartin Matuska (void)ctx;
330c03c5b1cSMartin Matuska function(opaque);
331c03c5b1cSMartin Matuska }
332c03c5b1cSMartin Matuska
POOL_tryAdd(POOL_ctx * ctx,POOL_function function,void * opaque)333c03c5b1cSMartin Matuska int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
334c03c5b1cSMartin Matuska (void)ctx;
335c03c5b1cSMartin Matuska function(opaque);
336c03c5b1cSMartin Matuska return 1;
337c03c5b1cSMartin Matuska }
338c03c5b1cSMartin Matuska
POOL_sizeof(POOL_ctx * ctx)339c03c5b1cSMartin Matuska size_t POOL_sizeof(POOL_ctx* ctx) {
340c03c5b1cSMartin Matuska if (ctx==NULL) return 0; /* supports sizeof NULL */
341c03c5b1cSMartin Matuska assert(ctx == &g_ctx);
342c03c5b1cSMartin Matuska return sizeof(*ctx);
343c03c5b1cSMartin Matuska }
344c03c5b1cSMartin Matuska
345c03c5b1cSMartin Matuska #endif /* ZSTD_MULTITHREAD */
346