diff options
Diffstat (limited to 'linuxthreads/manager.c')
-rw-r--r-- | linuxthreads/manager.c | 95 |
1 files changed, 86 insertions, 9 deletions
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c index daa12bc1f5..3b70097232 100644 --- a/linuxthreads/manager.c +++ b/linuxthreads/manager.c @@ -43,14 +43,17 @@ const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX; /* Indicate whether at least one thread has a user-defined stack (if 1), or if all threads have stacks supplied by LinuxThreads (if 0). */ -int __pthread_nonstandard_stacks = 0; +int __pthread_nonstandard_stacks; /* Number of active entries in __pthread_handles (used by gdb) */ volatile int __pthread_handles_num = 2; /* Whether to use debugger additional actions for thread creation (set to 1 by gdb) */ -volatile int __pthread_threads_debug = 0; +volatile int __pthread_threads_debug; + +/* Globally enabled events. */ +volatile td_thr_events_t __pthread_threads_events; /* Mapping from stack segment to thread descriptor. */ /* Stack segment numbers are also indices into the __pthread_handles array. */ @@ -80,7 +83,9 @@ static pthread_t pthread_threads_counter = 0; static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg, - sigset_t *mask, int father_pid); + sigset_t *mask, int father_pid, + int report_events, + td_thr_events_t *event_maskp); static void pthread_handle_free(pthread_t th_id); static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode); static void pthread_reap_children(void); @@ -141,7 +146,9 @@ int __pthread_manager(void *arg) request.req_args.create.fn, request.req_args.create.arg, &request.req_args.create.mask, - request.req_thread->p_pid); + request.req_thread->p_pid, + request.req_thread->p_report_events, + &request.req_thread->p_eventbuf.eventmask); restart(request.req_thread); break; case REQ_FREE: @@ -220,6 +227,19 @@ static int pthread_start_thread(void *arg) return 0; } +static int pthread_start_thread_event(void *arg) +{ + pthread_descr self = thread_self (); + + /* Get the lock the manager will free once all is correctly set up. */ + __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); + /* Free it immediately. */ + __pthread_unlock (THREAD_GETMEM(self, p_lock)); + + /* Continue with the real function. */ + return pthread_start_thread (arg); +} + static int pthread_allocate_stack(const pthread_attr_t *attr, pthread_descr default_new_thread, int pagesize, @@ -297,7 +317,9 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg, - sigset_t * mask, int father_pid) + sigset_t * mask, int father_pid, + int report_events, + td_thr_events_t *event_maskp) { size_t sseg; int pid; @@ -372,10 +394,47 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, new_thread->p_start_args.mask = *mask; /* Raise priority of thread manager if needed */ __pthread_manager_adjust_prio(new_thread->p_priority); - /* Do the cloning */ - pid = __clone(pthread_start_thread, (void **) new_thread, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - __pthread_sig_cancel, new_thread); + /* Do the cloning. We have to use two different functions depending + on whether we are debugging or not. */ + pid = 0; /* Note that the thread never can have PID zero. */ + if (report_events) + { + /* See whether the TD_CREATE event bit is set in any of the + masks. */ + int idx = __td_eventword (TD_CREATE); + uint32_t mask = __td_eventmask (TD_CREATE); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | event_maskp->event_bits[idx])) != 0) + { + /* Lock the mutex the child will use now so that it will stop. */ + __pthread_lock(new_thread->p_lock, NULL); + + /* We have to report this event. */ + pid = __clone(pthread_start_thread_event, (void **) new_thread, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); + if (pid != -1) + { + /* Now fill in the information about the new thread in + the newly created thread's data structure. We cannot let + the new thread do this since we don't know whether it was + already scheduled when we send the event. */ + new_thread->p_eventbuf.eventdata = new_thread; + new_thread->p_eventbuf.eventnum = TD_CREATE; + + /* Now call the function which signals the event. */ + __linuxthreads_create_event (); + + /* Now restart the thread. */ + __pthread_unlock(new_thread->p_lock); + } + } + } + if (pid == 0) + pid = __clone(pthread_start_thread, (void **) new_thread, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); /* Check if cloning succeeded */ if (pid == -1) { /* Free the stack if we allocated it */ @@ -451,6 +510,24 @@ static void pthread_exited(pid_t pid) /* Mark thread as exited, and if detached, free its resources */ __pthread_lock(th->p_lock, NULL); th->p_exited = 1; + /* If we have to signal this event do it now. */ + if (th->p_report_events) + { + /* See whether TD_DEATH is in any of the mask. */ + int idx = __td_eventword (TD_REAP); + uint32_t mask = __td_eventmask (TD_REAP); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | th->p_eventbuf.eventmask.event_bits[idx])) != 0) + { + /* Yep, we have to signal the death. */ + th->p_eventbuf.eventnum = TD_DEATH; + th->p_eventbuf.eventdata = th; + + /* Now call the function to signal the event. */ + __linuxthreads_reap_event(); + } + } detached = th->p_detached; __pthread_unlock(th->p_lock); if (detached) |