mirror of
https://github.com/3proxy/3proxy.git
synced 2026-11-05 09:25:49 +08:00
Event loops: the C library's resolver run on the thread's stack
glibc's getaddrinfo() sizes what it takes with alloca(), IPv6 most, by the thread's stack, not by the fiber's it may be called on: a client moved to a new configuration on a reload goes on on its fiber, and the new configuration's services may resolve with the system resolver, which otherwise is never called on a loop (threadperclient). A fiber yields to have it called on the loop thread's own stack (onthreadstack()), and goes on with its answer; the loop waits for it as the fiber would have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f2cc447f73
commit
7e3182ae89
68
src/common.c
68
src/common.c
@ -340,6 +340,8 @@ void (*fiberblockfunc)(SOCKET s, short events) = NULL;
|
||||
void (*fiberclosefunc)(SOCKET s) = NULL;
|
||||
/* set as well: whether this thread is a loop's, which is not to wait */
|
||||
int (*onloopfunc)(void) = NULL;
|
||||
/* and what runs func(arg) on the thread's own stack, not a fiber's */
|
||||
void (*onthreadstackfunc)(void (*func)(void *arg), void *arg) = NULL;
|
||||
#define BLOCKED(s, ev) do { if(fiberblockfunc && (errno == EAGAIN || errno == EWOULDBLOCK)) \
|
||||
fiberblockfunc((s), (ev)); } while(0)
|
||||
|
||||
@ -1174,12 +1176,45 @@ int afdetect(unsigned char *name){
|
||||
}
|
||||
|
||||
/* A name resolved the way a mode says: a service's names with its own */
|
||||
#if !defined(NOIPV6) && !defined(NOSTDRESOLVE)
|
||||
/* What the C library's resolver is asked, and its answer */
|
||||
struct stdresolve {
|
||||
unsigned char *name;
|
||||
int family;
|
||||
struct sockaddr *sa;
|
||||
uint32_t res;
|
||||
};
|
||||
|
||||
/* getaddrinfo(): run on a thread's own stack, which glibc may take much of,
|
||||
for IPv6 most (alloca() sized by the thread's stack, not a fiber's) */
|
||||
static void stdresolve46(void *arg){
|
||||
struct stdresolve *r = (struct stdresolve *)arg;
|
||||
struct addrinfo *ai, hint;
|
||||
|
||||
r->res = 0;
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
hint.ai_family = (r->family == 6 || r->family == 64)?AF_INET6:AF_INET;
|
||||
if (getaddrinfo((char *)r->name, NULL, &hint, &ai)) {
|
||||
if(r->family == 64 || r->family == 46){
|
||||
hint.ai_family = (r->family == 64)?AF_INET:AF_INET6;
|
||||
if (getaddrinfo((char *)r->name, NULL, &hint, &ai)) return;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
if(ai){
|
||||
if(ai->ai_addr->sa_family == AF_INET || ai->ai_addr->sa_family == AF_INET6){
|
||||
*SAFAMILY(r->sa)=ai->ai_addr->sa_family;
|
||||
memcpy(SAADDR(r->sa), SAADDR(ai->ai_addr), SAADDRLEN(ai->ai_addr));
|
||||
r->res = *SAFAMILY(r->sa);
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t getip46m(int mode, int family, unsigned char *name, struct sockaddr *sa){
|
||||
#ifndef NOIPV6
|
||||
int detect;
|
||||
#ifndef NOSTDRESOLVE
|
||||
struct addrinfo *ai, hint;
|
||||
#endif
|
||||
RESOLVFUNC tmpresolv;
|
||||
|
||||
if(!sa) return 0;
|
||||
@ -1210,23 +1245,16 @@ uint32_t getip46m(int mode, int family, unsigned char *name, struct sockaddr *s
|
||||
return 0;
|
||||
}
|
||||
#ifndef NOSTDRESOLVE
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
hint.ai_family = (family == 6 || family == 64)?AF_INET6:AF_INET;
|
||||
if (getaddrinfo((char *)name, NULL, &hint, &ai)) {
|
||||
if(family == 64 || family == 46){
|
||||
hint.ai_family = (family == 64)?AF_INET:AF_INET6;
|
||||
if (getaddrinfo((char *)name, NULL, &hint, &ai)) return 0;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
if(ai){
|
||||
if(ai->ai_addr->sa_family == AF_INET || ai->ai_addr->sa_family == AF_INET6){
|
||||
*SAFAMILY(sa)=ai->ai_addr->sa_family;
|
||||
memcpy(SAADDR(sa), SAADDR(ai->ai_addr), SAADDRLEN(ai->ai_addr));
|
||||
freeaddrinfo(ai);
|
||||
return *SAFAMILY(sa);
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
{
|
||||
struct stdresolve r;
|
||||
|
||||
r.name = name;
|
||||
r.family = family;
|
||||
r.sa = sa;
|
||||
/* a fiber's stack is not one to give it */
|
||||
if(onthreadstackfunc) (*onthreadstackfunc)(stdresolve46, &r);
|
||||
else stdresolve46(&r);
|
||||
return r.res;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@ -81,6 +81,9 @@ struct looper {
|
||||
unsigned nidle;
|
||||
struct sockreg **regs; /* by descriptor, the loop's thread only */
|
||||
unsigned nregs;
|
||||
/* what a fiber yielded to have run on the thread's stack */
|
||||
void (*stackcall)(void *arg);
|
||||
void *stackarg;
|
||||
};
|
||||
|
||||
/* what srvspawn() posts to a loop */
|
||||
@ -141,8 +144,16 @@ static void fibergive(struct looper *lp, struct fiberslot *fs){
|
||||
client is done. */
|
||||
static void fiberrun(struct looper *lp, struct fiber *f){
|
||||
struct fiberslot *fs = (struct fiberslot *)f;
|
||||
int alive;
|
||||
|
||||
if(!fiberresume(f)) fibergive(lp, fs);
|
||||
/* a call it asked for on the thread's stack made, and it goes on */
|
||||
while((alive = fiberresume(f)) && lp->stackcall){
|
||||
void (*call)(void *arg) = lp->stackcall;
|
||||
|
||||
lp->stackcall = NULL;
|
||||
call(lp->stackarg);
|
||||
}
|
||||
if(!alive) fibergive(lp, fs);
|
||||
/* in the middle of its client's code: started over from its stack's
|
||||
start for the next client, or freed where it cannot be */
|
||||
else if(fs->abandoned){
|
||||
@ -1132,6 +1143,20 @@ static unsigned ncpus(void){
|
||||
#endif
|
||||
}
|
||||
|
||||
/* onthreadstackfunc: func(arg) on the loop thread's own stack, for a fiber
|
||||
calling what wants a big one: the loop waits as long as it takes. */
|
||||
static void onthreadstack(void (*func)(void *arg), void *arg){
|
||||
struct looper *lp = curlooper;
|
||||
|
||||
if(!lp || !fibercurrent()){
|
||||
func(arg);
|
||||
return;
|
||||
}
|
||||
lp->stackcall = func;
|
||||
lp->stackarg = arg;
|
||||
fiberyield();
|
||||
}
|
||||
|
||||
/* The loops, started the first time a client is to be served on one, for
|
||||
the life of the process: as many as loops said then. 0 if they run. */
|
||||
static int loopsstart(void){
|
||||
@ -1191,6 +1216,7 @@ static int loopsstart(void){
|
||||
#endif
|
||||
fiberpollfunc = fiberpoll;
|
||||
onloopfunc = onlooper;
|
||||
onthreadstackfunc = onthreadstack;
|
||||
}
|
||||
_3proxy_mutex_unlock(&loops_mutex);
|
||||
return !i;
|
||||
|
||||
@ -340,6 +340,7 @@ extern int (*fiberpollfunc)(struct pollfd *fds, unsigned nfds, int timeout);
|
||||
extern void (*fiberblockfunc)(SOCKET s, short events);
|
||||
extern void (*fiberclosefunc)(SOCKET s);
|
||||
extern int (*onloopfunc)(void);
|
||||
extern void (*onthreadstackfunc)(void (*func)(void *arg), void *arg);
|
||||
int sockreadable(SOCKET s);
|
||||
#ifndef _WIN32
|
||||
int fdclose(int fd);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user