From 17a5287fce73067939d4a47b727ad280b39df73e Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Tue, 27 Oct 2026 19:46:10 +0300 Subject: [PATCH] Fibers: stacks of their own size, not a thread's A fiber's stack was a thread's, PTHREAD_STACK_MIN included: 128K on arm64 glibc, which is there for a thread's signals, and a loop's thread takes none. It is BASESTACKSIZE with the service's stacksize added, and the room kept for wolfSSL's handshake (TLSSTACKSIZE), as a thread's but for that. Only reserved either way: measured with OpenSSL, a fiber holds 8K to 12K of it, TLS handshakes included. Co-Authored-By: Claude Opus 5.5 --- src/mainclient.c | 2 +- src/mainloop.c | 14 +++++++++++--- src/proxymain.c | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/mainclient.c b/src/mainclient.c index ac1f2f0..f9f2f88 100644 --- a/src/mainclient.c +++ b/src/mainclient.c @@ -278,7 +278,7 @@ static int srvspawn(struct srvstart *s, SOCKET client_sock){ /* on a loop: what is posted to it made now, so that posting it, done once the client is counted, cannot fail */ - if(loopwanted(srv)) job = loopjobnew(need); + if(loopwanted(srv)) job = loopjobnew(srv->stacksize); /* an idle worker if one has the stack this service needs */ _3proxy_mutex_lock(&tpool.mutex); diff --git a/src/mainloop.c b/src/mainloop.c index 881f84f..d642301 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -100,7 +100,15 @@ static int loopsfailed; /* the loop of this thread, NULL but in a loop's thread */ static LTLS struct looper *curlooper; -static size_t fiberstack(size_t need){ +/* A fiber's stack: a thread's, the service's stacksize added, with room + kept for wolfSSL (TLSSTACKSIZE), which unless built for a small stack + takes much of it in a handshake; reserved only, a page held as it is + used. Not PTHREAD_STACK_MIN, which is for a thread's signals: a loop's + thread takes none. What the C library would want a big stack for, its + resolver, runs on the thread's own (onthreadstack()). */ +static size_t fiberstack(int extra){ + size_t need = BASESTACKSIZE + TLSSTACKSIZE + (extra > 0? (size_t)extra : 0); + #ifdef _WIN32 /* only reserved: Windows commits as it is used, and takes some for itself */ @@ -1233,7 +1241,7 @@ static int loopwanted(struct srvparam *srv){ } /* What srvspawn() hands to a loop, made before: posting cannot fail. */ -static struct loopjob *loopjobnew(size_t stacksize){ +static struct loopjob *loopjobnew(int stacksize){ struct loopjob *job = malloc(sizeof(*job)); if(job){ @@ -1264,7 +1272,7 @@ static int onlooper(void){ static int loopwanted(struct srvparam *srv){ return 0; } -static struct loopjob *loopjobnew(size_t stacksize){ +static struct loopjob *loopjobnew(int stacksize){ return NULL; } static void loopspawn(struct loopjob *job, struct clientparam *param){ diff --git a/src/proxymain.c b/src/proxymain.c index 6688a5b..0b2e1af 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -84,7 +84,7 @@ static int poolpark(struct clientparam *param); static int srvspawn(struct srvstart *s, SOCKET client_sock); struct loopjob; static int loopwanted(struct srvparam *srv); -static struct loopjob *loopjobnew(size_t stacksize); +static struct loopjob *loopjobnew(int stacksize); static void loopspawn(struct loopjob *job, struct clientparam *param); static int onlooper(void); static void filterswap(struct clientparam *param, unsigned char **cur, unsigned char *now);