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;
|
void (*fiberclosefunc)(SOCKET s) = NULL;
|
||||||
/* set as well: whether this thread is a loop's, which is not to wait */
|
/* set as well: whether this thread is a loop's, which is not to wait */
|
||||||
int (*onloopfunc)(void) = NULL;
|
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)) \
|
#define BLOCKED(s, ev) do { if(fiberblockfunc && (errno == EAGAIN || errno == EWOULDBLOCK)) \
|
||||||
fiberblockfunc((s), (ev)); } while(0)
|
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 */
|
/* 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){
|
uint32_t getip46m(int mode, int family, unsigned char *name, struct sockaddr *sa){
|
||||||
#ifndef NOIPV6
|
#ifndef NOIPV6
|
||||||
int detect;
|
int detect;
|
||||||
#ifndef NOSTDRESOLVE
|
|
||||||
struct addrinfo *ai, hint;
|
|
||||||
#endif
|
|
||||||
RESOLVFUNC tmpresolv;
|
RESOLVFUNC tmpresolv;
|
||||||
|
|
||||||
if(!sa) return 0;
|
if(!sa) return 0;
|
||||||
@ -1210,23 +1245,16 @@ uint32_t getip46m(int mode, int family, unsigned char *name, struct sockaddr *s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifndef NOSTDRESOLVE
|
#ifndef NOSTDRESOLVE
|
||||||
memset(&hint, 0, sizeof(hint));
|
{
|
||||||
hint.ai_family = (family == 6 || family == 64)?AF_INET6:AF_INET;
|
struct stdresolve r;
|
||||||
if (getaddrinfo((char *)name, NULL, &hint, &ai)) {
|
|
||||||
if(family == 64 || family == 46){
|
r.name = name;
|
||||||
hint.ai_family = (family == 64)?AF_INET:AF_INET6;
|
r.family = family;
|
||||||
if (getaddrinfo((char *)name, NULL, &hint, &ai)) return 0;
|
r.sa = sa;
|
||||||
}
|
/* a fiber's stack is not one to give it */
|
||||||
else return 0;
|
if(onthreadstackfunc) (*onthreadstackfunc)(stdresolve46, &r);
|
||||||
}
|
else stdresolve46(&r);
|
||||||
if(ai){
|
return r.res;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -81,6 +81,9 @@ struct looper {
|
|||||||
unsigned nidle;
|
unsigned nidle;
|
||||||
struct sockreg **regs; /* by descriptor, the loop's thread only */
|
struct sockreg **regs; /* by descriptor, the loop's thread only */
|
||||||
unsigned nregs;
|
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 */
|
/* what srvspawn() posts to a loop */
|
||||||
@ -141,8 +144,16 @@ static void fibergive(struct looper *lp, struct fiberslot *fs){
|
|||||||
client is done. */
|
client is done. */
|
||||||
static void fiberrun(struct looper *lp, struct fiber *f){
|
static void fiberrun(struct looper *lp, struct fiber *f){
|
||||||
struct fiberslot *fs = (struct fiberslot *)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
|
/* 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 */
|
start for the next client, or freed where it cannot be */
|
||||||
else if(fs->abandoned){
|
else if(fs->abandoned){
|
||||||
@ -1132,6 +1143,20 @@ static unsigned ncpus(void){
|
|||||||
#endif
|
#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 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. */
|
the life of the process: as many as loops said then. 0 if they run. */
|
||||||
static int loopsstart(void){
|
static int loopsstart(void){
|
||||||
@ -1191,6 +1216,7 @@ static int loopsstart(void){
|
|||||||
#endif
|
#endif
|
||||||
fiberpollfunc = fiberpoll;
|
fiberpollfunc = fiberpoll;
|
||||||
onloopfunc = onlooper;
|
onloopfunc = onlooper;
|
||||||
|
onthreadstackfunc = onthreadstack;
|
||||||
}
|
}
|
||||||
_3proxy_mutex_unlock(&loops_mutex);
|
_3proxy_mutex_unlock(&loops_mutex);
|
||||||
return !i;
|
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 (*fiberblockfunc)(SOCKET s, short events);
|
||||||
extern void (*fiberclosefunc)(SOCKET s);
|
extern void (*fiberclosefunc)(SOCKET s);
|
||||||
extern int (*onloopfunc)(void);
|
extern int (*onloopfunc)(void);
|
||||||
|
extern void (*onthreadstackfunc)(void (*func)(void *arg), void *arg);
|
||||||
int sockreadable(SOCKET s);
|
int sockreadable(SOCKET s);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int fdclose(int fd);
|
int fdclose(int fd);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user