commit 4eb647c97d6b989ac97314c1ed2da4200507f76b
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-05-30T07:28:20Z |
| subject | Configurable worker count |
commit 4eb647c97d6b989ac97314c1ed2da4200507f76b
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-05-30T07:28:20Z
Configurable worker count
---
docs/tinyproxy.1.scd | 4 ++++
docs/tinyproxy.conf.5.scd | 5 ++++-
examples/tinyproxy.conf | 5 +++--
src/compat_cpu.c | 33 +++++++++++++++++++++++++++++++++
src/compat_cpu.h | 6 ++++++
src/klog.c | 12 ++++++++++--
src/klog.h | 2 ++
src/tinyproxy.c | 37 ++++++++++++++++++++++++++++++++++---
src/worker.c | 1 +
src/worker_pool.c | 11 +++++++----
src/x_builtins.c | 22 ++++++++++++++++++----
src/x_builtins.h | 1 +
12 files changed, 123 insertions(+), 16 deletions(-)
diff --git a/docs/tinyproxy.1.scd b/docs/tinyproxy.1.scd
index e05f1e6..56c74a5 100644
--- a/docs/tinyproxy.1.scd
+++ b/docs/tinyproxy.1.scd
@@ -31,6 +31,10 @@ Routes may be configured using a config file or directly from the command line w
# OPTIONS
+*-w* <workers>
+ Number of worker threads. 0 = auto (one per CPU).
+ Default 1
+
*-c* <config>
Load configuration file.
diff --git a/docs/tinyproxy.conf.5.scd b/docs/tinyproxy.conf.5.scd
index 02f599c..93e58f8 100644
--- a/docs/tinyproxy.conf.5.scd
+++ b/docs/tinyproxy.conf.5.scd
@@ -66,11 +66,14 @@ builtin close
- TCP: Accepts the connection and immediately closes it without reading or writing.
- UDP: this is equivalent to discard/drop because UDP has no connection to close.
-buitin http-ok
+buitin http_ok
Returns "HTTP/1.1 200 OK\\r\\nContent-Length: 2\\r\\nConnection: close\\r\\n\\r\\nOK" then close.
Useful for probing
+buitin log_conn
+ Logs the connection.
+
# EXAMPLES
Forward HTTPS:
diff --git a/examples/tinyproxy.conf b/examples/tinyproxy.conf
index f556b7d..f2e93e9 100644
--- a/examples/tinyproxy.conf
+++ b/examples/tinyproxy.conf
@@ -18,14 +18,15 @@ listen tcp :12995 builtin client_addr
listen tcp :12996 builtin hang idle_timeout=3,connect_timeout=1
listen tcp :12997 builtin discard
listen tcp :12998 builtin close
-listen tcp :8080 builtin http-ok
+listen tcp :12999 builtin log_conn
+listen tcp :8080 builtin http_ok
# Builtin UDP test backends.
listen udp :12995 builtin client_addr
listen udp :12996 builtin hang
listen udp :12997 builtin discard
listen udp :12998 builtin close
-listen udp :8080 builtin http-ok
+listen udp :8080 builtin http_ok
# Static file TCP backends.
listen tcp :14000 file examples/http-response.txt
diff --git a/src/compat_cpu.c b/src/compat_cpu.c
new file mode 100644
index 0000000..a7f4287
--- /dev/null
+++ b/src/compat_cpu.c
@@ -0,0 +1,33 @@
+#include "compat_cpu.h"
+
+#include <limits.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+int compat_cpu_count(void)
+{
+#ifdef _WIN32
+ SYSTEM_INFO si;
+
+ GetSystemInfo(&si);
+
+ if (si.dwNumberOfProcessors == 0 ||
+ si.dwNumberOfProcessors > INT_MAX) {
+ return 1;
+ }
+
+ return (int)si.dwNumberOfProcessors;
+#else
+ long n = sysconf(_SC_NPROCESSORS_ONLN);
+
+ if (n < 1 || n > INT_MAX) {
+ return 1;
+ }
+
+ return (int)n;
+#endif
+}
diff --git a/src/compat_cpu.h b/src/compat_cpu.h
new file mode 100644
index 0000000..4a3a77b
--- /dev/null
+++ b/src/compat_cpu.h
@@ -0,0 +1,6 @@
+#ifndef COMPAT_CPU_H
+#define COMPAT_CPU_H
+
+int compat_cpu_count(void);
+
+#endif
diff --git a/src/klog.c b/src/klog.c
index c053c03..158a2ae 100644
--- a/src/klog.c
+++ b/src/klog.c
@@ -7,6 +7,13 @@
#include "klog.h"
#include "route.h"
+static _Thread_local int klog_worker_id = -1;
+
+void klog_set_worker_id(int id)
+{
+ klog_worker_id = id;
+}
+
static int localtime_compat(const time_t *t, struct tm *out)
{
#ifdef _WIN32
@@ -109,13 +116,14 @@ void log_at(char sev, const char *file, int line, const char *msg, ...)
strftime(tbuf, sizeof(tbuf), "%m%d %H:%M:%S", &tm);
- fprintf(stderr, "%c%s.%06ld %7ld %s:%d] msg=",
+ fprintf(stderr, "%c%s.%06ld %7ld %s:%d] worker=%u msg=",
sev,
tbuf,
ts.tv_nsec / 1000,
(long)compat_getpid(),
file,
- line);
+ line,
+ klog_worker_id);
print_quoted_value(msg);
diff --git a/src/klog.h b/src/klog.h
index 5601a5f..c0b73f1 100644
--- a/src/klog.h
+++ b/src/klog.h
@@ -31,6 +31,8 @@ struct log_value {
} v;
};
+void klog_set_worker_id(int id);
+
void log_at(char sev, const char *file, int line, const char *msg, ...);
static inline struct log_value log_value_str(const char *v)
diff --git a/src/tinyproxy.c b/src/tinyproxy.c
index 7066cca..691c7a0 100644
--- a/src/tinyproxy.c
+++ b/src/tinyproxy.c
@@ -1,6 +1,7 @@
#include <event2/event.h>
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -10,6 +11,7 @@
#include "klog.h"
#include "signals.h"
#include "file_conf.h"
+#include "compat_cpu.h"
#include "worker_pool.h"
#include "route.h"
#include "route_runtime.h"
@@ -20,6 +22,7 @@ static void usage(FILE *out, const char *prog)
"usage: %s [-c config-file | -L route]\n"
"\n"
"options:\n"
+ " -w N Number of worker threads. 0 = auto (one per CPU). Default 1\n"
" -c FILE path to config file (default: tinyproxy.conf)\n"
" -L ROUTE add inline route, same syntax as config line\n"
" may be specified multiple times\n"
@@ -45,6 +48,7 @@ static void prevent_socket_write_from_killing_process(void)
int main(int argc, char **argv)
{
prevent_socket_write_from_killing_process();
+ klog_set_worker_id(0);
int opt;
int exit_code = 1;
@@ -60,6 +64,8 @@ int main(int argc, char **argv)
int wsa_started = 0;
#endif
+ size_t worker_count = 1;
+
const char *conf_path = NULL;
struct route *routes = NULL;
size_t route_count = 0;
@@ -71,8 +77,34 @@ int main(int argc, char **argv)
struct signal_events signals;
int signals_started = 0;
- while ((opt = getopt(argc, argv, "c:L:h:v")) != -1) {
+ while ((opt = getopt(argc, argv, "c:L:w:h:v")) != -1) {
switch (opt) {
+ case 'w': {
+ char *end = NULL;
+ unsigned long n;
+
+ if (optarg == NULL || optarg[0] == '\0') {
+ LOG_ERROR("missing number after -w");
+ return 2;
+ }
+
+ errno = 0;
+ n = strtoul(optarg, &end, 10);
+
+ if (errno == ERANGE || end == optarg || *end != '\0' || n > INT_MAX) {
+ LOG_ERROR("invalid worker count", "value", _LOGV(optarg));
+ return 2;
+ }
+
+ worker_count = (int)n;
+
+ if(worker_count == 0) {
+ worker_count = compat_cpu_count();
+ }
+
+ break;
+ }
+
case 'c':
if (optarg == NULL || optarg[0] == '\0') {
LOG_ERROR("missing config path after -c");
@@ -219,11 +251,10 @@ int main(int argc, char **argv)
signals_started = 1;
struct worker_pool wpool;
- size_t worker_count = 1;
rc = worker_pool_init(&wpool, worker_count);
if (rc != 0) {
- LOG_ERROR("failed to init worker pool", "err", _LOGV(rc));
+ LOG_ERROR("failed to init worker pool", "err", _LOGV(strerror(rc)));
goto out;
}
worker_pool_ready = true;
diff --git a/src/worker.c b/src/worker.c
index ce9c753..126e272 100644
--- a/src/worker.c
+++ b/src/worker.c
@@ -99,6 +99,7 @@ static void worker_process_pending(struct worker *w)
static void *worker_main(void *arg)
{
struct worker *w = arg;
+ klog_set_worker_id(w->id);
event_base_dispatch(w->base);
diff --git a/src/worker_pool.c b/src/worker_pool.c
index 410a3b3..ac9c748 100644
--- a/src/worker_pool.c
+++ b/src/worker_pool.c
@@ -1,9 +1,10 @@
-#include "worker_pool.h"
-
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include "klog.h"
+#include "worker_pool.h"
+
int worker_pool_init(struct worker_pool *pool, size_t count)
{
size_t i;
@@ -22,7 +23,7 @@ int worker_pool_init(struct worker_pool *pool, size_t count)
pool->count = count;
for (i = 0; i < count; i++) {
- int rc = worker_init(&pool->workers[i], (unsigned int)i);
+ int rc = worker_init(&pool->workers[i], (unsigned int)(i + 1));
if (rc != 0) {
while (i > 0) {
i--;
@@ -37,6 +38,8 @@ int worker_pool_init(struct worker_pool *pool, size_t count)
}
}
+ LOG_INFO("worker pool initialized", "workers", _LOGV(count));
+
return 0;
}
@@ -118,4 +121,4 @@ struct worker *worker_pool_next(struct worker_pool *pool)
pool->next++;
return w;
-}
\ No newline at end of file
+}
diff --git a/src/x_builtins.c b/src/x_builtins.c
index ef0d233..5969250 100644
--- a/src/x_builtins.c
+++ b/src/x_builtins.c
@@ -1,9 +1,10 @@
-#include "x_builtins.h"
-
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include "klog.h"
+#include "x_builtins.h"
+
int x_builtin_parse(const char *s, enum x_builtin_upstream *out)
{
if (s == NULL || out == NULL) {
@@ -25,11 +26,16 @@ int x_builtin_parse(const char *s, enum x_builtin_upstream *out)
return 0;
}
- if (strcmp(s, "http-ok") == 0) {
+ if (strcmp(s, "http_ok") == 0) {
*out = X_BUILTIN_HTTP_OK;
return 0;
}
+ if (strcmp(s, "log_conn") == 0) {
+ *out = X_BUILTIN_LOG_CONN;
+ return 0;
+ }
+
if (strcmp(s, "close") == 0) {
*out = X_BUILTIN_CLOSE;
return 0;
@@ -53,7 +59,9 @@ const char *x_builtin_name(enum x_builtin_upstream builtin)
case X_BUILTIN_HANG:
return "hang";
case X_BUILTIN_HTTP_OK:
- return "http-ok";
+ return "http_ok";
+ case X_BUILTIN_LOG_CONN:
+ return "log_conn";
case X_BUILTIN_CLOSE:
return "close";
case X_BUILTIN_NONE:
@@ -108,6 +116,12 @@ int x_builtin_handle(
res->action = X_BUILTIN_ACTION_DISCARD;
return 0;
+ case X_BUILTIN_LOG_CONN:
+ LOG_INFO("log_conn", "client_addr", _LOGV(req->client_addr));
+ res->data_len = 0;
+ res->action = X_BUILTIN_ACTION_CLOSE;
+ return 0;
+
case X_BUILTIN_CLOSE:
res->data_len = 0;
res->action = X_BUILTIN_ACTION_CLOSE;
diff --git a/src/x_builtins.h b/src/x_builtins.h
index e152874..bcc5a77 100644
--- a/src/x_builtins.h
+++ b/src/x_builtins.h
@@ -10,6 +10,7 @@ enum x_builtin_upstream {
X_BUILTIN_DISCARD,
X_BUILTIN_HANG,
X_BUILTIN_HTTP_OK,
+ X_BUILTIN_LOG_CONN,
X_BUILTIN_CLOSE,
};