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