source: trunk/libs/newlib/src/newlib/libc/sys/linux/linuxthreads/join.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 7.2 KB
Line 
1/* Linuxthreads - a simple clone()-based implementation of Posix        */
2/* threads for Linux.                                                   */
3/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4/*                                                                      */
5/* This program is free software; you can redistribute it and/or        */
6/* modify it under the terms of the GNU Library General Public License  */
7/* as published by the Free Software Foundation; either version 2       */
8/* of the License, or (at your option) any later version.               */
9/*                                                                      */
10/* This program is distributed in the hope that it will be useful,      */
11/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
13/* GNU Library General Public License for more details.                 */
14
15/* Thread termination and joining */
16
17#include <errno.h>
18#include <sched.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include "pthread.h"
22#include "internals.h"
23#include "spinlock.h"
24#include "restart.h"
25
26void pthread_exit(void * retval)
27{
28  __pthread_do_exit (retval, CURRENT_STACK_FRAME);
29}
30
31void __pthread_do_exit(void *retval, char *currentframe)
32{
33  pthread_descr self = thread_self();
34  pthread_descr joining;
35  struct pthread_request request;
36
37  /* Reset the cancellation flag to avoid looping if the cleanup handlers
38     contain cancellation points */
39  THREAD_SETMEM(self, p_canceled, 0);
40  /* Call cleanup functions and destroy the thread-specific data */
41  __pthread_perform_cleanup(currentframe);
42  __pthread_destroy_specifics();
43  /* Store return value */
44  __pthread_lock(THREAD_GETMEM(self, p_lock), self);
45  THREAD_SETMEM(self, p_retval, retval);
46  /* See whether we have to signal the death.  */
47  if (THREAD_GETMEM(self, p_report_events))
48    {
49      /* See whether TD_DEATH is in any of the mask.  */
50      int idx = __td_eventword (TD_DEATH);
51      uint32_t mask = __td_eventmask (TD_DEATH);
52
53      if ((mask & (__pthread_threads_events.event_bits[idx]
54                   | THREAD_GETMEM_NC(self,
55                                      p_eventbuf.eventmask.event_bits[idx])))
56          != 0)
57        {
58          /* Yep, we have to signal the death.  */
59          THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH);
60          THREAD_SETMEM(self, p_eventbuf.eventdata, self);
61          __pthread_last_event = self;
62
63          /* Now call the function to signal the event.  */
64          __linuxthreads_death_event();
65        }
66    }
67  /* Say that we've terminated */
68  THREAD_SETMEM(self, p_terminated, 1);
69  /* See if someone is joining on us */
70  joining = THREAD_GETMEM(self, p_joining);
71  __pthread_unlock(THREAD_GETMEM(self, p_lock));
72  /* Restart joining thread if any */
73  if (joining != NULL) restart(joining);
74  /* If this is the initial thread, block until all threads have terminated.
75     If another thread calls exit, we'll be terminated from our signal
76     handler. */
77  if (self == __pthread_main_thread && __pthread_manager_request >= 0) {
78    request.req_thread = self;
79    request.req_kind = REQ_MAIN_THREAD_EXIT;
80    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
81                                    (char *)&request, sizeof(request)));
82    suspend(self);
83    /* Main thread flushes stdio streams and runs atexit functions.
84       It also calls a handler within LinuxThreads which sends a process exit
85       request to the thread manager. */
86    exit(0);
87  }
88  /* Threads other than the main one  terminate without flushing stdio streams
89     or running atexit functions. */
90  _exit(0);
91}
92
93/* Function called by pthread_cancel to remove the thread from
94   waiting on a condition variable queue. */
95
96static int join_extricate_func(void *obj, pthread_descr th)
97{
98  volatile pthread_descr self = thread_self();
99  pthread_handle handle = obj;
100  pthread_descr jo;
101  int did_remove = 0;
102
103  __pthread_lock(&handle->h_lock, self);
104  jo = handle->h_descr;
105  did_remove = jo->p_joining != NULL;
106  jo->p_joining = NULL;
107  __pthread_unlock(&handle->h_lock);
108
109  return did_remove;
110}
111
112int pthread_join(pthread_t thread_id, void ** thread_return)
113{
114  volatile pthread_descr self = thread_self();
115  struct pthread_request request;
116  pthread_handle handle = thread_handle(thread_id);
117  pthread_descr th;
118  pthread_extricate_if extr;
119  int already_canceled = 0;
120
121  /* Set up extrication interface */
122  extr.pu_object = handle;
123  extr.pu_extricate_func = join_extricate_func;
124
125  __pthread_lock(&handle->h_lock, self);
126  if (nonexisting_handle(handle, thread_id)) {
127    __pthread_unlock(&handle->h_lock);
128    return ESRCH;
129  }
130  th = handle->h_descr;
131  if (th == self) {
132    __pthread_unlock(&handle->h_lock);
133    return EDEADLK;
134  }
135  /* If detached or already joined, error */
136  if (th->p_detached || th->p_joining != NULL) {
137    __pthread_unlock(&handle->h_lock);
138    return EINVAL;
139  }
140  /* If not terminated yet, suspend ourselves. */
141  if (! th->p_terminated) {
142    /* Register extrication interface */
143    __pthread_set_own_extricate_if(self, &extr);
144    if (!(THREAD_GETMEM(self, p_canceled)
145        && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
146      th->p_joining = self;
147    else
148      already_canceled = 1;
149    __pthread_unlock(&handle->h_lock);
150
151    if (already_canceled) {
152      __pthread_set_own_extricate_if(self, 0);
153      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
154    }
155
156    suspend(self);
157    /* Deregister extrication interface */
158    __pthread_set_own_extricate_if(self, 0);
159
160    /* This is a cancellation point */
161    if (THREAD_GETMEM(self, p_woken_by_cancel)
162        && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
163      THREAD_SETMEM(self, p_woken_by_cancel, 0);
164      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
165    }
166    __pthread_lock(&handle->h_lock, self);
167  }
168  /* Get return value */
169  if (thread_return != NULL) *thread_return = th->p_retval;
170  __pthread_unlock(&handle->h_lock);
171  /* Send notification to thread manager */
172  if (__pthread_manager_request >= 0) {
173    request.req_thread = self;
174    request.req_kind = REQ_FREE;
175    request.req_args.free.thread_id = thread_id;
176    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
177                                    (char *) &request, sizeof(request)));
178  }
179  return 0;
180}
181
182int pthread_detach(pthread_t thread_id)
183{
184  int terminated;
185  struct pthread_request request;
186  pthread_handle handle = thread_handle(thread_id);
187  pthread_descr th;
188
189  __pthread_lock(&handle->h_lock, NULL);
190  if (nonexisting_handle(handle, thread_id)) {
191    __pthread_unlock(&handle->h_lock);
192    return ESRCH;
193  }
194  th = handle->h_descr;
195  /* If already detached, error */
196  if (th->p_detached) {
197    __pthread_unlock(&handle->h_lock);
198    return EINVAL;
199  }
200  /* If already joining, don't do anything. */
201  if (th->p_joining != NULL) {
202    __pthread_unlock(&handle->h_lock);
203    return 0;
204  }
205  /* Mark as detached */
206  th->p_detached = 1;
207  terminated = th->p_terminated;
208  __pthread_unlock(&handle->h_lock);
209  /* If already terminated, notify thread manager to reclaim resources */
210  if (terminated && __pthread_manager_request >= 0) {
211    request.req_thread = thread_self();
212    request.req_kind = REQ_FREE;
213    request.req_args.free.thread_id = thread_id;
214    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
215                                    (char *) &request, sizeof(request)));
216  }
217  return 0;
218}
Note: See TracBrowser for help on using the repository browser.