diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/internal/pthread_impl.h | 1 | ||||
| -rw-r--r-- | src/thread/pthread_create.c | 19 | 
2 files changed, 16 insertions, 4 deletions
| diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index adb80f2f..c1740111 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -36,6 +36,7 @@ struct pthread {  	struct __ptcb *cancelbuf;  	void **tsd;  	pthread_attr_t attr; +	volatile int dead;  };  #define __SU (sizeof(size_t)/sizeof(int)) diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 9c24b844..d829fa26 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -25,13 +25,16 @@ void __pthread_unwind_next(struct __ptcb *cb)  		}  	} -	syscall4(__NR_rt_sigprocmask, SIG_BLOCK, (long)(uint64_t[1]){-1},0,8); +	/* Mark this thread dead before decrementing count */ +	self->dead = 1;  	if (!a_fetch_add(&libc.threads_minus_1, -1))  		exit(0); -	if (self->detached && self->map_base) +	if (self->detached && self->map_base) { +		syscall4(__NR_rt_sigprocmask, SIG_BLOCK, (long)(uint64_t[1]){-1},0,8);  		__unmapself(self->map_base, self->map_size); +	}  	__syscall_exit(0);  } @@ -76,9 +79,17 @@ static struct {  static void rsyscall_handler(int sig, siginfo_t *si, void *ctx)  { -	if (si->si_code > 0 || si->si_pid != __pthread_self()->pid) return; +	struct pthread *self = __pthread_self(); + +	if (si->si_code > 0 || si->si_pid != self->pid || +		rs.cnt == libc.threads_minus_1) return; -	if (rs.cnt == libc.threads_minus_1) return; +	/* Threads which have already decremented themselves from the +	 * thread count must not increment rs.cnt or otherwise act. */ +	if (self->dead) { +		__wait(&rs.hold, 0, 1, 1); +		return; +	}  	if (syscall6(rs.nr, rs.arg[0], rs.arg[1], rs.arg[2],  		rs.arg[3], rs.arg[4], rs.arg[5]) < 0 && !rs.err) rs.err=errno; | 
