curl-curl/tests/unit/unit3300.c
Stefan Eissing 6f9f4b3cb7
lib: add thread pool and queue
- new source files for thread pool and queue
- test cases 3217 and 3218 for them
- internal documentation

Closes #20916
2026-03-23 23:03:58 +01:00

165 lines
5.5 KiB
C

/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "unitcheck.h"
#include "curlx/wait.h"
#include "thrdpool.h"
#ifdef USE_THREADS
struct unit3300_ctx {
uint32_t total;
uint32_t taken;
uint32_t returned;
};
static uint32_t unit3300_item = 23;
static uint32_t unit3300_delay_ms = 0;
static void unit3300_ctx_init(struct unit3300_ctx *ctx,
uint32_t total,
uint32_t delay_ms)
{
memset(ctx, 0, sizeof(*ctx));
ctx->total = total;
unit3300_delay_ms = delay_ms;
}
static void *unit3300_take(void *user_data, const char **pdescription,
timediff_t *ptimeout_ms)
{
struct unit3300_ctx *ctx = user_data;
*pdescription = NULL;
*ptimeout_ms = 0;
if(ctx->taken < ctx->total) {
ctx->taken++;
return &unit3300_item;
}
return NULL;
}
static void unit3300_process(void *item)
{
fail_unless(item == &unit3300_item, "process unexpected item");
if(unit3300_delay_ms) {
curlx_wait_ms(unit3300_delay_ms);
}
}
static void unit3300_return(void *item, void *user_data)
{
struct unit3300_ctx *ctx = user_data;
(void)item;
if(ctx) {
ctx->returned++;
fail_unless(ctx->returned <= ctx->total, "returned too many");
}
}
static CURLcode test_unit3300(const char *arg)
{
UNITTEST_BEGIN_SIMPLE
struct curl_thrdpool *tpool;
struct unit3300_ctx ctx;
CURLcode r;
/* pool without minimum, will not start anything */
unit3300_ctx_init(&ctx, 10, 0);
r = Curl_thrdpool_create(&tpool, "unit3300a", 0, 2, 0,
unit3300_take, unit3300_process, unit3300_return,
&ctx);
fail_unless(!r, "pool-a create");
Curl_thrdpool_destroy(tpool, TRUE);
fail_unless(!ctx.returned, "pool-a unexpected items returned");
fail_unless(!ctx.taken, "pool-a unexpected items taken");
/* pool without minimum, signal start, consumes everything */
unit3300_ctx_init(&ctx, 10, 0);
r = Curl_thrdpool_create(&tpool, "unit3300b", 0, 2, 0,
unit3300_take, unit3300_process, unit3300_return,
&ctx);
fail_unless(!r, "pool-b create");
r = Curl_thrdpool_signal(tpool, 2);
fail_unless(!r, "pool-b signal");
Curl_thrdpool_await_idle(tpool, 0);
Curl_thrdpool_destroy(tpool, TRUE);
fail_unless(ctx.returned == ctx.total, "pool-b items returned missing");
fail_unless(ctx.taken == ctx.total, "pool-b items taken missing");
/* pool with minimum, consumes everything without signal */
unit3300_ctx_init(&ctx, 10, 0);
r = Curl_thrdpool_create(&tpool, "unit3300c", 1, 2, 0,
unit3300_take, unit3300_process, unit3300_return,
&ctx);
fail_unless(!r, "pool-c create");
Curl_thrdpool_await_idle(tpool, 0);
Curl_thrdpool_destroy(tpool, TRUE);
fail_unless(ctx.returned == ctx.total, "pool-c items returned missing");
fail_unless(ctx.taken == ctx.total, "pool-c items taken missing");
/* pool with many max, signal abundance, consumes everything */
unit3300_ctx_init(&ctx, 100, 0);
r = Curl_thrdpool_create(&tpool, "unit3300d", 0, 50, 0,
unit3300_take, unit3300_process, unit3300_return,
&ctx);
fail_unless(!r, "pool-d create");
r = Curl_thrdpool_signal(tpool, 100);
fail_unless(!r, "pool-d signal");
Curl_thrdpool_await_idle(tpool, 0);
Curl_thrdpool_destroy(tpool, TRUE);
fail_unless(ctx.returned == ctx.total, "pool-d items returned missing");
fail_unless(ctx.taken == ctx.total, "pool-d items taken missing");
/* pool with 1 max, many to take, no await, destroy without join */
unit3300_ctx_init(&ctx, 10000000, 1);
r = Curl_thrdpool_create(&tpool, "unit3300e", 0, 1, 0,
unit3300_take, unit3300_process, unit3300_return,
&ctx);
fail_unless(!r, "pool-e create");
r = Curl_thrdpool_signal(tpool, 100);
fail_unless(!r, "pool-e signal");
Curl_thrdpool_destroy(tpool, FALSE);
fail_unless(ctx.returned < ctx.total, "pool-e returned all");
fail_unless(ctx.taken < ctx.total, "pool-e took all");
#ifdef DEBUGBUILD
/* pool thread will notice destruction and should immediately abort.
* No memory leak should be reported. if the wait is too short on
* a slow system, thread sanitizer will freak out as memdebug will
* be called by threads after main thread shut down. */
curlx_wait_ms(1000);
#endif
UNITTEST_END_SIMPLE
}
#else
static CURLcode test_unit3300(const char *arg)
{
UNITTEST_BEGIN_SIMPLE
(void)arg;
UNITTEST_END_SIMPLE
}
#endif /* USE_THREADS */