void __stack_smash_handler(char func[], int damaged) { extern char *__progname; const char message[] = ": stack smashing attack in function "; struct sigaction sa; sigset_t mask; sigfillset(&mask); sigdelset(&mask, SSP_SIGTYPE); /* Block all signal handlers */ sigprocmask(SIG_BLOCK, &mask, NULL); /* except SSP_SIGTYPE */ /* Print error message to stderr and syslog */ #if 1 /* syslog() causes issues with glibc #94325 */ __libc_write(STDERR_FILENO, __progname, strlen(__progname)); __libc_write(STDERR_FILENO, message, strlen(message)); __libc_write(STDERR_FILENO, func, strlen(func)); __libc_write(STDERR_FILENO, "()\n", 3); //_syscall3(int, _ssp_syslog, int, type, char *, bufp, int, len) //_ssp_syslog(LOG_INFO, #else fprintf(stderr, "%s%s%s()\n", __progname, message, func); syslog(LOG_INFO, "%s%s%s()", __progname, message, func); #endif /* Make the default handler associated with the signal handler */ memset(&sa, 0, sizeof(struct sigaction)); sigfillset(&sa.sa_mask); /* Block all signals */ sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigaction(SSP_SIGTYPE, &sa, NULL); (void) kill(getpid(), SSP_SIGTYPE); _exit(127); }
int pthread_join(pthread_t th, void **thread_return) { volatile pthread_t self = thread_self(); struct pthread_request request; if (th == self) return EDEADLK; /* If detached or already joined, error */ if (th->p_detached || th->p_joining != NULL) { return EINVAL; } /* If not terminated yet, suspend ourselves. */ if (! th->p_terminated) { th->p_joining = self; suspend(self); } /* Get return value */ if (thread_return != NULL) *thread_return = th->p_retval; /* Send notification to thread manager */ if (__pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_FREE; request.req_args.free.thread = th; __libc_write(__pthread_manager_request, (char *) &request, sizeof(request)); } return 0; }
int pthread_detach(pthread_t th) { int terminated; struct pthread_request request; acquire(&th->p_spinlock); /* If already detached, error */ if (th->p_detached) { release(&th->p_spinlock); return EINVAL; } /* If already joining, don't do anything. */ if (th->p_joining != NULL) { release(&th->p_spinlock); return 0; } /* Mark as detached */ th->p_detached = 1; terminated = th->p_terminated; release(&th->p_spinlock); /* If already terminated, notify thread manager to reclaim resources */ if (terminated && __pthread_manager_request >= 0) { request.req_thread = thread_self(); request.req_kind = REQ_FREE; request.req_args.free.thread = th; __libc_write(__pthread_manager_request, (char *) &request, sizeof(request)); } return 0; }
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg) { pthread_descr self = thread_self(); struct pthread_request request; if (__pthread_manager_request < 0) { if (__pthread_initialize_manager() < 0) return EAGAIN; } request.req_thread = self; request.req_kind = REQ_CREATE; request.req_args.create.attr = attr; request.req_args.create.fn = start_routine; request.req_args.create.arg = arg; sigprocmask(SIG_SETMASK, (const sigset_t *) NULL, &request.req_args.create.mask); PDEBUG("write REQ_CREATE to manager thread\n"); TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); PDEBUG("before suspend(self)\n"); suspend(self); PDEBUG("after suspend(self)\n"); if (THREAD_GETMEM(self, p_retcode) == 0) *thread = (pthread_t) THREAD_GETMEM(self, p_retval); return THREAD_GETMEM(self, p_retcode); }
void __assert_fail (const char *assertion, const char *file, unsigned int line, const char *function) { char *buf; #ifdef FATAL_PREPARE FATAL_PREPARE; #endif if (__asprintf (&buf, _("%s%s%s:%u: %s%sAssertion `%s' failed.\n"), __progname, __progname[0] ? ": " : "", file, line, function ? function : "", function ? ": " : "", assertion) >= 0) { /* Print the message. */ (void) __fxprintf (NULL, "%s", buf); (void) fflush (stderr); /* We have to free the old buffer since the application might catch the SIGABRT signal. */ char *old = atomic_exchange_acq (&__abort_msg, buf); free (old); } else { /* At least print a minimal message. */ static const char errstr[] = "Unexpected error.\n"; __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); } abort (); }
ssize_t pwrite (int fd, const void *buf, size_t nbyte, off_t offset) { /* Since we must not change the file pointer preserve the value so that we can restore it later. */ int save_errno; ssize_t result; off_t old_offset = __libc_lseek (fd, 0, SEEK_CUR); if (old_offset == (off_t) -1) return -1; /* Set to wanted position. */ if (__libc_lseek (fd, offset, SEEK_SET) == (off_t) -1) return -1; /* Write out the data. */ result = __libc_write (fd, buf, nbyte); /* Now we have to restore the position. If this fails we have to return this as an error. But if the writing also failed we return this error. */ save_errno = errno; if (__libc_lseek (fd, old_offset, SEEK_SET) == (off_t) -1) { if (result == -1) __set_errno (save_errno); return -1; } __set_errno (save_errno); return result; }
void pthread_exit(void * retval) { pthread_t self = thread_self(); pthread_t joining; struct pthread_request request; /* Reset the cancellation flag to avoid looping if the cleanup handlers contain cancellation points */ self->p_canceled = 0; /* Call cleanup functions and destroy the thread-specific data */ __pthread_perform_cleanup(); __pthread_destroy_specifics(); /* Store return value */ acquire(&self->p_spinlock); self->p_retval = retval; /* Say that we've terminated */ self->p_terminated = 1; /* See if someone is joining on us */ joining = self->p_joining; release(&self->p_spinlock); /* Restart joining thread if any */ if (joining != NULL) restart(joining); /* If this is the initial thread, block until all threads have terminated. If another thread calls exit, we'll be terminated from our signal handler. */ if (self == __pthread_main_thread && __pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_MAIN_THREAD_EXIT; __libc_write(__pthread_manager_request, (char *)&request, sizeof(request)); suspend(self); } /* Exit the process (but don't flush stdio streams, and don't run atexit functions). */ _exit(0); }
void __assert_perror_fail (int errnum, const char *file, unsigned int line, const char *function) { char errbuf[1024]; char *buf; #ifdef FATAL_PREPARE FATAL_PREPARE; #endif if (__asprintf (&buf, _("%s%s%s:%u: %s%sUnexpected error: %s.\n"), __progname, __progname[0] ? ": " : "", file, line, function ? function : "", function ? ": " : "", __strerror_r (errnum, errbuf, sizeof errbuf)) >= 0) { /* Print the message. */ (void) __fxprintf (NULL, "%s", buf); (void) fflush (stderr); /* We have to free the buffer since the appplication might catch the SIGABRT. */ free (buf); } else { /* At least print a minimal message. */ static const char errstr[] = "Unexpected error.\n"; __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); } abort (); }
void __pthread_message(char * fmt, ...) { char buffer[1024]; va_list args; sprintf(buffer, "%05d : ", __getpid()); va_start(args, fmt); vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args); va_end(args); TEMP_FAILURE_RETRY(__libc_write(2, buffer, strlen(buffer))); }
int fputc_unlocked(int c, FILE *stream) { if (!__likely(stream->flags&CANWRITE) || __fflush4(stream,0)) { kaputt: stream->flags|=ERRORINDICATOR; return EOF; } if (__unlikely(stream->bm>=stream->buflen-1)) if (fflush_unlocked(stream)) goto kaputt; if (stream->flags&NOBUF) { #if __BYTE_ORDER == __LITTLE_ENDIAN if (__libc_write(stream->fd,&c,1) != 1) #else if (__libc_write(stream->fd,(char*)&c+sizeof(c)-1,1) != 1) #endif goto kaputt; return 0; } stream->buf[stream->bm]=c; ++stream->bm; if (((stream->flags&BUFLINEWISE) && c=='\n') || ((stream->flags&NOBUF))) /* puke */ if (fflush_unlocked(stream)) goto kaputt; return 0; }
void __assert_fail_base (const char *fmt, const char *assertion, const char *file, unsigned int line, const char *function) { char *str; #ifdef FATAL_PREPARE FATAL_PREPARE; #endif int total; if (__asprintf (&str, fmt, __progname, __progname[0] ? ": " : "", file, line, function ? function : "", function ? ": " : "", assertion, &total) >= 0) { /* Print the message. */ (void) __fxprintf (NULL, "%s", str); (void) fflush (stderr); total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1); struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (__builtin_expect (buf != MAP_FAILED, 1)) { buf->size = total; strcpy (buf->msg, str); /* We have to free the old buffer since the application might catch the SIGABRT signal. */ struct abort_msg_s *old = atomic_exchange_acq (&__abort_msg, buf); if (old != NULL) __munmap (old, old->size); } free (str); } else { /* At least print a minimal message. */ static const char errstr[] = "Unexpected error.\n"; __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); } abort (); }
/* Process creation */ static int attribute_noreturn pthread_start_thread(void *arg) { pthread_descr self = (pthread_descr) arg; struct pthread_request request; void * outcome; /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif PDEBUG("\n"); /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, getpid()); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) /* Explicit scheduling attributes were provided: apply them */ sched_setscheduler(THREAD_GETMEM(self, p_pid), THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); else if (__pthread_manager_thread.p_priority > 0) /* Default scheduling required, but thread manager runs in realtime scheduling: switch new thread to SCHED_OTHER policy */ { struct sched_param default_params; default_params.sched_priority = 0; sched_setscheduler(THREAD_GETMEM(self, p_pid), SCHED_OTHER, &default_params); } /* Make gdb aware of new thread */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, p_start_args.arg)); /* Exit with the given return value */ __pthread_do_exit(outcome, CURRENT_STACK_FRAME); }
void __pthread_manager_sighandler(int sig attribute_unused) { int kick_manager = terminated_children == 0 && main_thread_exiting; terminated_children = 1; /* If the main thread is terminating, kick the thread manager loop each time some threads terminate. This eliminates a two second shutdown delay caused by the thread manager sleeping in the call to __poll(). Instead, the thread manager is kicked into action, reaps the outstanding threads and resumes the main thread so that it can complete the shutdown. */ if (kick_manager) { struct pthread_request request; request.req_thread = 0; request.req_kind = REQ_KICK; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); } }
/* Delete a key */ int pthread_key_delete(pthread_key_t key) { pthread_descr self = thread_self(); pthread_mutex_lock(&pthread_keys_mutex); if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) { pthread_mutex_unlock(&pthread_keys_mutex); return EINVAL; } pthread_keys[key].in_use = 0; pthread_keys[key].destr = NULL; /* Set the value of the key to NULL in all running threads, so that if the key is reallocated later by pthread_key_create, its associated values will be NULL in all threads. Do nothing if no threads have been created yet. */ if (__pthread_manager_request != -1) { struct pthread_key_delete_helper_args args; struct pthread_request request; args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; args.self = 0; request.req_thread = self; request.req_kind = REQ_FOR_EACH_THREAD; request.req_args.for_each.arg = &args; request.req_args.for_each.fn = pthread_key_delete_helper; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } pthread_mutex_unlock(&pthread_keys_mutex); return 0; }
int __new_sem_post(sem_t * sem) { pthread_descr self = thread_self(); pthread_descr th; struct pthread_request request; if (THREAD_GETMEM(self, p_in_sighandler) == NULL) { __pthread_lock(&sem->__sem_lock, self); if (sem->__sem_waiting == NULL) { if (sem->__sem_value >= SEM_VALUE_MAX) { /* Overflow */ errno = ERANGE; __pthread_unlock(&sem->__sem_lock); return -1; } sem->__sem_value++; __pthread_unlock(&sem->__sem_lock); } else { th = dequeue(&sem->__sem_waiting); __pthread_unlock(&sem->__sem_lock); th->p_sem_avail = 1; WRITE_MEMORY_BARRIER(); restart(th); } } else { /* If we're in signal handler, delegate post operation to the thread manager. */ if (__pthread_manager_request < 0) { if (__pthread_initialize_manager() < 0) { errno = EAGAIN; return -1; } } request.req_kind = REQ_POST; request.req_args.post = sem; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); } return 0; }
void __assert_fail (const char *assertion, const char *file, unsigned int line, const char *function) { char *buf; #ifdef FATAL_PREPARE FATAL_PREPARE; #endif if (__asprintf (&buf, _("%s%s%s:%u: %s%sAssertion `%s' failed.\n"), __progname, __progname[0] ? ": " : "", file, line, function ? function : "", function ? ": " : "", assertion) >= 0) { /* Print the message. */ #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) __fwprintf (stderr, L"%s", buf); else #endif (void) fputs (buf, stderr); (void) fflush (stderr); /* We have to free the buffer since the application might catch the SIGABRT. */ free (buf); } else { /* At least print a minimal message. */ static const char errstr[] = "Unexpected error.\n"; __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); } abort (); }
static void pthread_onexit_process(int retcode, void *arg) { struct pthread_request request; pthread_descr self = thread_self(); if (__pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_PROCESS_EXIT; request.req_args.exit.code = retcode; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); /* Main thread should accumulate times for thread manager and its children, so that timings for main thread account for all threads. */ if (self == __pthread_main_thread) { waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); /* Since all threads have been asynchronously terminated * (possibly holding locks), free cannot be used any more. */ __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; } } }
int pthread_join(pthread_t th, void ** thread_return) { volatile pthread_t self = thread_self(); struct pthread_request request; if (th == self) return EDEADLK; acquire(&th->p_spinlock); /* If detached or already joined, error */ if (th->p_detached || th->p_joining != NULL) { release(&th->p_spinlock); return EINVAL; } /* If not terminated yet, suspend ourselves. */ if (! th->p_terminated) { th->p_joining = self; release(&th->p_spinlock); suspend_with_cancellation(self); acquire(&th->p_spinlock); /* This is a cancellation point */ if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { th->p_joining = NULL; release(&th->p_spinlock); pthread_exit(PTHREAD_CANCELED); } } /* Get return value */ if (thread_return != NULL) *thread_return = th->p_retval; release(&th->p_spinlock); /* Send notification to thread manager */ if (__pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_FREE; request.req_args.free.thread = th; __libc_write(__pthread_manager_request, (char *) &request, sizeof(request)); } return 0; }
int pthread_detach(pthread_t thread_id) { int terminated; struct pthread_request request; pthread_handle handle = thread_handle(thread_id); pthread_descr th; __pthread_lock(&handle->h_lock, NULL); if (invalid_handle(handle, thread_id)) { __pthread_unlock(&handle->h_lock); return ESRCH; } th = handle->h_descr; /* If already detached, error */ if (th->p_detached) { __pthread_unlock(&handle->h_lock); return EINVAL; } /* If already joining, don't do anything. */ if (th->p_joining != NULL) { __pthread_unlock(&handle->h_lock); return 0; } /* Mark as detached */ th->p_detached = 1; terminated = th->p_terminated; __pthread_unlock(&handle->h_lock); /* If already terminated, notify thread manager to reclaim resources */ if (terminated && __pthread_manager_request >= 0) { request.req_thread = thread_self(); request.req_kind = REQ_FREE; request.req_args.free.thread_id = thread_id; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); } return 0; }
int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg) { pthread_descr self = thread_self(); struct pthread_request request; int retval; if (__builtin_expect (__pthread_manager_request, 0) < 0) { if (__pthread_initialize_manager() < 0) return EAGAIN; } request.req_thread = self; request.req_kind = REQ_CREATE; request.req_args.create.attr = attr; request.req_args.create.fn = start_routine; request.req_args.create.arg = arg; sigprocmask(SIG_SETMASK, (const sigset_t *) NULL, &request.req_args.create.mask); TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); retval = THREAD_GETMEM(self, p_retcode); if (__builtin_expect (retval, 0) == 0) *thread = (pthread_t) THREAD_GETMEM(self, p_retval); return retval; }
ssize_t write(int fd, const void *buf, size_t count) { __TEST_CANCEL(); return __libc_write(fd,buf,count); }
void __libc_vsyslog(int priority, const char *format, va_list arg_ptr) { char buffer[BUF_SIZE]; char time_buf[20]; int buflen, headerlen; time_t now; struct tm now_tm; pid_t pid; int fd; int sigpipe; struct sigaction action, oldaction; int saved_errno = errno; /* check for invalid priority/facility bits */ if (priority & ~(LOG_PRIMASK|LOG_FACMASK)) { syslog(LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID, "syslog: unknown facility/priorityority: %x", priority); priority &= LOG_PRIMASK|LOG_FACMASK; } /* check priority against setlogmask */ if ((LOG_MASK(LOG_PRI(priority)) && LogMask) == 0) return; /* Set default facility if none specified. */ if ((priority & LOG_FACMASK) == 0) priority |= LogFacility; pid = getpid(); time(&now); strftime(time_buf, 20, "%h %e %T", localtime_r (&now, &now_tm)); if (LogStat & LOG_PID) headerlen = snprintf(buffer, 130, "<%d>%s %s[%ld]: ", priority, time_buf, LogTag, (long) pid); else headerlen = snprintf(buffer, 130, "<%d>%s %s: ", priority, time_buf, LogTag); if (!LogTag[0]) { if ((LogStat & LOG_PID) != LOG_PID) headerlen = snprintf(buffer, 130, "<%d>%s (unknown)[%ld]: ", priority, time_buf, (long) pid); strcat(buffer+headerlen, "syslog without openlog w/ ident, please check code!"); buflen = 41; } else { errno=saved_errno; buflen = vsnprintf(buffer+headerlen, BUF_SIZE - headerlen, format, arg_ptr); } if (LogStat & LOG_PERROR) { __libc_write(1, buffer+headerlen, buflen); if (buffer[headerlen+buflen] != '\n') __libc_write(1,"\n", 1); } /* prepare for broken connection */ memset(&action, 0, sizeof(action)); action.sa_handler = SIG_IGN; sigemptyset(&action.sa_mask); sigpipe = sigaction (SIGPIPE, &action, &oldaction); if (!connected) openlog_intern(LogStat | LOG_NDELAY, 0); /* If we have a SOCK_STREAM connection, also send ASCII NUL as a * record terminator. */ if (LogType == SOCK_STREAM) buflen++; if (!connected || (send(LogFile, buffer, buflen+headerlen, 0) != buflen+headerlen)) { if (LogType == SOCK_STREAM) buflen--; closelog_intern(); /* * Output the message to the console; don't worry about blocking, * if console blocks everything will. Make sure the error reported * is the one from the syslogd failure. */ if ((LogStat & LOG_CONS) && ((fd = __libc_open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0)) { __libc_write(fd, buffer, buflen+headerlen); __libc_write(fd, "\r\n", 2); __libc_close(fd); } } if (sigpipe == 0) sigaction(SIGPIPE, &oldaction, (struct sigaction *) NULL); }
int __pthread_initialize_manager(void) { int manager_pipe[2]; int pid; int report_events; struct pthread_request request; *__libc_multiple_threads_ptr = 1; /* If basic initialization not done yet (e.g. we're called from a constructor run before our constructor), do it now */ if (__pthread_initial_thread_bos == NULL) pthread_initialize(); /* Setup stack for thread manager */ __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); if (__pthread_manager_thread_bos == NULL) return -1; __pthread_manager_thread_tos = __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; /* On non-MMU systems we make sure that the initial thread bounds don't overlap * with the manager stack frame */ NOMMU_INITIAL_THREAD_BOUNDS(__pthread_manager_thread_tos,__pthread_manager_thread_bos); PDEBUG("manager stack: size=%d, bos=%p, tos=%p\n", THREAD_MANAGER_STACK_SIZE, __pthread_manager_thread_bos, __pthread_manager_thread_tos); #if 0 PDEBUG("initial stack: estimate bos=%p, tos=%p\n", __pthread_initial_thread_bos, __pthread_initial_thread_tos); #endif /* Setup pipe to communicate with thread manager */ if (pipe(manager_pipe) == -1) { free(__pthread_manager_thread_bos); return -1; } /* Start the thread manager */ pid = 0; #ifdef USE_TLS if (__linuxthreads_initial_report_events != 0) THREAD_SETMEM (((pthread_descr) NULL), p_report_events, __linuxthreads_initial_report_events); report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events); #else if (__linuxthreads_initial_report_events != 0) __pthread_initial_thread.p_report_events = __linuxthreads_initial_report_events; report_events = __pthread_initial_thread.p_report_events; #endif if (__builtin_expect (report_events, 0)) { /* It's a bit more complicated. We have to report the creation of the manager thread. */ int idx = __td_eventword (TD_CREATE); uint32_t mask = __td_eventmask (TD_CREATE); if ((mask & (__pthread_threads_events.event_bits[idx] | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) != 0) { __pthread_lock(__pthread_manager_thread.p_lock, NULL); #ifdef __ia64__ pid = __clone2(__pthread_manager_event, (void **) __pthread_manager_thread_tos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #else pid = clone(__pthread_manager_event, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #endif 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. */ __pthread_manager_thread.p_eventbuf.eventdata = &__pthread_manager_thread; __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; __pthread_last_event = &__pthread_manager_thread; __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Now call the function which signals the event. */ __linuxthreads_create_event (); } /* Now restart the thread. */ __pthread_unlock(__pthread_manager_thread.p_lock); } } if (pid == 0) { #ifdef __ia64__ pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_tos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #else pid = clone(__pthread_manager, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #endif } if (pid == -1) { free(__pthread_manager_thread_bos); __libc_close(manager_pipe[0]); __libc_close(manager_pipe[1]); return -1; } __pthread_manager_request = manager_pipe[1]; /* writing end */ __pthread_manager_reader = manager_pipe[0]; /* reading end */ __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Make gdb aware of new thread manager */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { raise(__pthread_sig_debug); /* We suspend ourself and gdb will wake us up when it is ready to handle us. */ __pthread_wait_for_restart_signal(thread_self()); } /* Synchronize debugging of the thread manager */ PDEBUG("send REQ_DEBUG to manager thread\n"); request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); return 0; }
size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, FILE *stream) { ssize_t res; size_t len=size*nmemb; size_t i,done; if (!__likely(stream->flags&CANWRITE) || __fflush4(stream,0)) { kaputt: stream->flags|=ERRORINDICATOR; return 0; } if (!nmemb || len/nmemb!=size) return 0; /* check for integer overflow */ if (__unlikely(len>stream->buflen || (stream->flags&NOBUF))) { if (fflush_unlocked(stream)) return 0; do { res=__libc_write(stream->fd,ptr,len); } while (res==-1 && errno==EINTR); } else again: { /* try to make the common case fast */ size_t todo=stream->buflen-stream->bm; if (todo>len) todo=len; if (todo) { if (stream->flags&BUFLINEWISE) { if (__unlikely((stream->flags&CHECKLINEWISE)!=0)) { stream->flags&=~CHECKLINEWISE; /* stdout is set to BUFLINEWISE|CHECKLINEWISE by default. */ /* that means we should check whether it is connected to a * tty on first flush, and if not so, reset BUFLINEWISE */ if (!isatty(stream->fd)) { stream->flags&=~BUFLINEWISE; goto notlinewise; } } for (i=0; i<todo; ++i) { if ((stream->buf[stream->bm++]=((char*)ptr)[i])=='\n') { if (fflush_unlocked(stream)) goto kaputt; } } } else { notlinewise: memcpy(stream->buf+stream->bm,ptr,todo); stream->bm+=todo; if (stream->bm==stream->buflen) { if (fflush_unlocked(stream)) return 0; /* if we are here, we should not have an empty buffer */ len-=todo; if (!len) return nmemb; ptr+=todo; goto again; } else return nmemb; } done=todo; } else done=0; for (i=done; i<len; ++i) if (fputc_unlocked(((char*)ptr)[i],stream) == EOF) { res=len-i; goto abort; } res=len; } if (res<0) { stream->flags|=ERRORINDICATOR; return 0; } abort: return size?res/size:0; }
int pthread_join(pthread_t thread_id, void ** thread_return) { volatile pthread_descr self = thread_self(); struct pthread_request request; pthread_handle handle = thread_handle(thread_id); pthread_descr th; pthread_extricate_if extr; int already_canceled = 0; PDEBUG("\n"); /* Set up extrication interface */ extr.pu_object = handle; extr.pu_extricate_func = join_extricate_func; __pthread_lock(&handle->h_lock, self); if (invalid_handle(handle, thread_id)) { __pthread_unlock(&handle->h_lock); return ESRCH; } th = handle->h_descr; if (th == self) { __pthread_unlock(&handle->h_lock); return EDEADLK; } /* If detached or already joined, error */ if (th->p_detached || th->p_joining != NULL) { __pthread_unlock(&handle->h_lock); return EINVAL; } /* If not terminated yet, suspend ourselves. */ if (! th->p_terminated) { /* Register extrication interface */ __pthread_set_own_extricate_if(self, &extr); if (!(THREAD_GETMEM(self, p_canceled) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) th->p_joining = self; else already_canceled = 1; __pthread_unlock(&handle->h_lock); if (already_canceled) { __pthread_set_own_extricate_if(self, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } PDEBUG("before suspend\n"); suspend(self); PDEBUG("after suspend\n"); /* Deregister extrication interface */ __pthread_set_own_extricate_if(self, 0); /* This is a cancellation point */ if (THREAD_GETMEM(self, p_woken_by_cancel) && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { THREAD_SETMEM(self, p_woken_by_cancel, 0); __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } __pthread_lock(&handle->h_lock, self); } /* Get return value */ if (thread_return != NULL) *thread_return = th->p_retval; __pthread_unlock(&handle->h_lock); /* Send notification to thread manager */ if (__pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_FREE; request.req_args.free.thread_id = thread_id; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); } return 0; }
void __pthread_do_exit(void *retval, char *currentframe) { pthread_descr self = thread_self(); pthread_descr joining; struct pthread_request request; PDEBUG("self=%p, pid=%d\n", self, self->p_pid); /* obey POSIX behavior and prevent cancellation functions from * being called more than once. * http://sourceware.org/ml/libc-ports/2006-10/msg00043.html */ THREAD_SETMEM(self, p_cancelstate, PTHREAD_CANCEL_DISABLE); THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); /* Call cleanup functions and destroy the thread-specific data */ __pthread_perform_cleanup(currentframe); __pthread_destroy_specifics(); /* Store return value */ __pthread_lock(THREAD_GETMEM(self, p_lock), self); THREAD_SETMEM(self, p_retval, retval); /* See whether we have to signal the death. */ if (THREAD_GETMEM(self, p_report_events)) { /* See whether TD_DEATH is in any of the mask. */ int idx = __td_eventword (TD_DEATH); uint32_t mask = __td_eventmask (TD_DEATH); if ((mask & (__pthread_threads_events.event_bits[idx] | THREAD_GETMEM_NC(self, p_eventbuf.eventmask).event_bits[idx])) != 0) { /* Yep, we have to signal the death. */ THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH); THREAD_SETMEM(self, p_eventbuf.eventdata, self); __pthread_last_event = self; /* Now call the function to signal the event. */ __linuxthreads_death_event(); } } /* Say that we've terminated */ THREAD_SETMEM(self, p_terminated, 1); /* See if someone is joining on us */ joining = THREAD_GETMEM(self, p_joining); PDEBUG("joining = %p, pid=%d\n", joining, joining->p_pid); __pthread_unlock(THREAD_GETMEM(self, p_lock)); /* Restart joining thread if any */ if (joining != NULL) restart(joining); /* If this is the initial thread, block until all threads have terminated. If another thread calls exit, we'll be terminated from our signal handler. */ if (self == __pthread_main_thread && __pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_MAIN_THREAD_EXIT; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *)&request, sizeof(request))); suspend(self); /* Main thread flushes stdio streams and runs atexit functions. * It also calls a handler within LinuxThreads which sends a process exit * request to the thread manager. */ exit(0); } /* Exit the process (but don't flush stdio streams, and don't run atexit functions). */ _exit(0); }
int __pthread_initialize_manager(void) { int manager_pipe[2]; int pid; struct pthread_request request; #ifndef HAVE_Z_NODELETE if (__builtin_expect (&__dso_handle != NULL, 1)) __cxa_atexit ((void (*) (void *)) pthread_atexit_retcode, NULL, __dso_handle); #endif if (__pthread_max_stacksize == 0) __pthread_init_max_stacksize (); /* If basic initialization not done yet (e.g. we're called from a constructor run before our constructor), do it now */ if (__pthread_initial_thread_bos == NULL) pthread_initialize(); /* Setup stack for thread manager */ __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); if (__pthread_manager_thread_bos == NULL) return -1; __pthread_manager_thread_tos = __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; /* Setup pipe to communicate with thread manager */ if (__libc_pipe(manager_pipe) == -1) { free(__pthread_manager_thread_bos); return -1; } /* Start the thread manager */ pid = 0; if (__builtin_expect (__pthread_initial_thread.p_report_events, 0)) { /* It's a bit more complicated. We have to report the creation of the manager thread. */ int idx = __td_eventword (TD_CREATE); uint32_t mask = __td_eventmask (TD_CREATE); if ((mask & (__pthread_threads_events.event_bits[idx] | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) != 0) { __pthread_lock(__pthread_manager_thread.p_lock, NULL); #ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager_event, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #elif _STACK_GROWS_UP pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #else pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #endif 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. */ __pthread_manager_thread.p_eventbuf.eventdata = &__pthread_manager_thread; __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; __pthread_last_event = &__pthread_manager_thread; __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Now call the function which signals the event. */ __linuxthreads_create_event (); } /* Now restart the thread. */ __pthread_unlock(__pthread_manager_thread.p_lock); } } if (__builtin_expect (pid, 0) == 0) { #ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #elif _STACK_GROWS_UP pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #else pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #endif } if (__builtin_expect (pid, 0) == -1) { free(__pthread_manager_thread_bos); __libc_close(manager_pipe[0]); __libc_close(manager_pipe[1]); return -1; } __pthread_manager_request = manager_pipe[1]; /* writing end */ __pthread_manager_reader = manager_pipe[0]; /* reading end */ __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Make gdb aware of new thread manager */ if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0) { raise(__pthread_sig_debug); /* We suspend ourself and gdb will wake us up when it is ready to handle us. */ __pthread_wait_for_restart_signal(thread_self()); } /* Synchronize debugging of the thread manager */ request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); return 0; }
void __nptl_main (void) { __libc_write (STDOUT_FILENO, banner, sizeof banner - 1); _exit (0); }