mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-21 06:25:43 +00:00
BUG/MEDIUM: splice/threads: pipe reuse list was not protected.
The list is now protected using a global spinlock.
This commit is contained in:
parent
926fa4c098
commit
d8b3b65faa
@ -174,6 +174,7 @@ enum lock_label {
|
||||
DNS_LOCK,
|
||||
PID_LIST_LOCK,
|
||||
EMAIL_ALERTS_LOCK,
|
||||
PIPES_LOCK,
|
||||
LOCK_LABELS
|
||||
};
|
||||
struct lock_stat {
|
||||
@ -262,7 +263,8 @@ static inline void show_lock_stats()
|
||||
"UPDATED_SERVERS", "LBPRM", "SIGNALS", "STK_TABLE", "STK_SESS",
|
||||
"APPLETS", "PEER", "BUF_WQ", "STREAMS", "SSL", "SSL_GEN_CERTS",
|
||||
"PATREF", "PATEXP", "PATLRU", "VARS", "COMP_POOL", "LUA",
|
||||
"NOTIF", "SPOE_APPLET", "DNS", "PID_LIST", "EMAIL_ALERTS" };
|
||||
"NOTIF", "SPOE_APPLET", "DNS", "PID_LIST", "EMAIL_ALERTS",
|
||||
"PIPES" };
|
||||
int lbl;
|
||||
|
||||
for (lbl = 0; lbl < LOCK_LABELS; lbl++) {
|
||||
|
38
src/pipe.c
38
src/pipe.c
@ -21,6 +21,7 @@
|
||||
|
||||
struct pool_head *pool2_pipe = NULL;
|
||||
struct pipe *pipes_live = NULL; /* pipes which are still ready to use */
|
||||
HA_SPINLOCK_T pipes_lock; /* lock used to protect pipes list */
|
||||
int pipes_used = 0; /* # of pipes in use (2 fds each) */
|
||||
int pipes_free = 0; /* # of pipes unused */
|
||||
|
||||
@ -30,6 +31,7 @@ static void init_pipe()
|
||||
pool2_pipe = create_pool("pipe", sizeof(struct pipe), MEM_F_SHARED);
|
||||
pipes_used = 0;
|
||||
pipes_free = 0;
|
||||
HA_SPIN_INIT(&pipes_lock);
|
||||
}
|
||||
|
||||
/* return a pre-allocated empty pipe. Try to allocate one if there isn't any
|
||||
@ -37,27 +39,28 @@ static void init_pipe()
|
||||
*/
|
||||
struct pipe *get_pipe()
|
||||
{
|
||||
struct pipe *ret;
|
||||
struct pipe *ret = NULL;
|
||||
int pipefd[2];
|
||||
|
||||
HA_SPIN_LOCK(PIPES_LOCK, &pipes_lock);
|
||||
if (likely(pipes_live)) {
|
||||
ret = pipes_live;
|
||||
pipes_live = pipes_live->next;
|
||||
pipes_free--;
|
||||
pipes_used++;
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pipes_used >= global.maxpipes)
|
||||
return NULL;
|
||||
goto out;
|
||||
|
||||
ret = pool_alloc2(pool2_pipe);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
goto out;
|
||||
|
||||
if (pipe(pipefd) < 0) {
|
||||
pool_free2(pool2_pipe, ret);
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
#ifdef F_SETPIPE_SZ
|
||||
if (global.tune.pipesize)
|
||||
@ -68,18 +71,28 @@ struct pipe *get_pipe()
|
||||
ret->cons = pipefd[0];
|
||||
ret->next = NULL;
|
||||
pipes_used++;
|
||||
out:
|
||||
HA_SPIN_UNLOCK(PIPES_LOCK, &pipes_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void inline __kill_pipe(struct pipe *p)
|
||||
{
|
||||
close(p->prod);
|
||||
close(p->cons);
|
||||
pool_free2(pool2_pipe, p);
|
||||
pipes_used--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* destroy a pipe, possibly because an error was encountered on it. Its FDs
|
||||
* will be closed and it will not be reinjected into the live pool.
|
||||
*/
|
||||
void kill_pipe(struct pipe *p)
|
||||
{
|
||||
close(p->prod);
|
||||
close(p->cons);
|
||||
pool_free2(pool2_pipe, p);
|
||||
pipes_used--;
|
||||
HA_SPIN_LOCK(PIPES_LOCK, &pipes_lock);
|
||||
__kill_pipe(p);
|
||||
HA_SPIN_UNLOCK(PIPES_LOCK, &pipes_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -89,14 +102,17 @@ void kill_pipe(struct pipe *p)
|
||||
*/
|
||||
void put_pipe(struct pipe *p)
|
||||
{
|
||||
HA_SPIN_LOCK(PIPES_LOCK, &pipes_lock);
|
||||
if (p->data) {
|
||||
kill_pipe(p);
|
||||
return;
|
||||
__kill_pipe(p);
|
||||
goto out;
|
||||
}
|
||||
p->next = pipes_live;
|
||||
pipes_live = p;
|
||||
pipes_free++;
|
||||
pipes_used--;
|
||||
out:
|
||||
HA_SPIN_UNLOCK(PIPES_LOCK, &pipes_lock);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user