/* * Wait for an event to happen. * * If holds != NULL, the caller holds the mutex, which will be released * before going to sleep. The thread calling thread_signal_cond *must* hold * the same mutex. * * The holds mutex is reacquired after wakeup. */ int thread_wait_cond (void *event, dk_mutex_t *holds, TVAL timeout) { thread_t *thr = current_thread; dk_mutex_t *mtx; int ok; thr->thr_status = WAITEVENT; thr->thr_event = event ? event : &_ev_never; thr->thr_event_pipe = -1; mtx = holds ? holds : _q_lock; Q_LOCK (); do { thread_queue_to (&_waitq, thr); _thread_num_wait++; if (holds) Q_UNLOCK (); if (timeout == TV_INFINITE) ok = pthread_cond_wait (thr->thr_cv, &mtx->mtx_mtx); else { struct timespec to; struct timeval now; gettimeofday (&now, NULL); to.tv_sec = now.tv_sec + timeout / 1000; to.tv_nsec = now.tv_usec + 1000 * (timeout % 1000); if (to.tv_nsec > 1000000) { to.tv_nsec -= 1000000; to.tv_sec++; } ok = pthread_cond_timedwait (thr->thr_cv, &mtx->mtx_mtx, &to); } if (holds) Q_LOCK (); thread_queue_remove (&_waitq, thr); _thread_num_wait--; } while (ok == 0 && thr->thr_event); Q_UNLOCK (); CKRET (ok); failed: thr->thr_status = RUNNING; return thr->thr_event == NULL ? 0 : -1; }
/* * Wake up all threads waiting for an event. */ int thread_signal_cond (void *event) { thread_t *thr; thread_t *next; int count; char dummy; count = 0; Q_LOCK (); for (thr = (thread_t *) _waitq.thq_head.thr_next; thr != (thread_t *) &_waitq.thq_head; thr = next) { next = (thread_t *) thr->thr_hdr.thr_next; if (thr->thr_event == event) { thr->thr_event = NULL; if (thr->thr_event_pipe == -1) pthread_cond_signal (thr->thr_cv); else /* * Wake up the select * XXX Should fix this - only one thread can safely wait * for an event in thread_select at a time. */ write (thr->thr_event_pipe, &dummy, 1); count++; } } Q_UNLOCK (); return count; }
/*=========================================================================== FUNCTION Q_LAST_CHECK DESCRIPTION This function returns a pointer to the link of the item at the tail of the specified queue. The item is not removed from the queue. DEPENDENCIES The specified queue should have been initialized previously via a call to q_init. RETURN VALUE The link of the last item in the queue, or NULL if there are no items on the queue. SIDE EFFECTS Pointer to link of an item on the queue is returned without de-queuing the item. ===========================================================================*/ void *q_last_check ( q_type *q_ptr /* Queue from which the item is returned */ ) { q_link_type *link_ptr = NULL; /* Link to be returned */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); /*------------------------------------------------------------------------- If there are items on the queue, return the last item -------------------------------------------------------------------------*/ Q_LOCK( q_ptr ); if( 0 < q_ptr->link_cnt ) { link_ptr = q_ptr->tail_link_ptr; } Q_FREE( q_ptr ); return (void *)link_ptr; } /* q_last_check */
/*=========================================================================== FUNCTION Q_CHECK DESCRIPTION This function returns a pointer to the link of the item at the head of the queue. The item is not removed from the queue. DEPENDENCIES The specified queue should have been initialized previously via a call to q_init. RETURN VALUE A pointer to the first queued item's link. If the specified queue is empty, then NULL is returned. SIDE EFFECTS Pointer to link of an item in the queue is returned without de-queuing the item. ===========================================================================*/ void *q_check ( q_type *q_ptr /* Pointer to a queue */ ) { q_link_type *link_ptr = NULL; /* link pointer to be returned */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameter -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); /*------------------------------------------------------------------------- Return the first link if there is an item on the queue. -------------------------------------------------------------------------*/ Q_LOCK( q_ptr ); if( 0 < q_ptr->link_cnt ) { link_ptr = q_ptr->head_link.next_link_ptr; } Q_FREE( q_ptr ); return (void *)link_ptr; } /* q_check() */
void qRemove(queueObj_t *qObj, void *data, size_t nSize) { Q_LOCK(&qObj->qMutex); NODE *node = qObj->qHead; if (!qObj->qHead || !qObj->qTail) { goto end; } if(qObj->qHead == qObj->qTail) { node = qObj->qHead; qObj->qHead = qObj->qTail = NULL; --qObj->qCount; } else { qObj->qHead = qObj->qHead->next; node->next = NULL; qObj->qHead->prev = NULL; --qObj->qCount; } if(data) { memcpy(data, node->data, nSize); } end: FREE(node); Q_UNLOCK(&qObj->qMutex); }
/*=========================================================================== FUNCTION Q_NEXT DESCRIPTION This function returns a pointer to the item link which comes after the specified item on the specified queue. DEPENDENCIES The specified queue should have been initialized previously via a call to q_init. The specified link should have been acquired from a previous call to q_check/q_next. RETURN VALUE A pointer to the next item on the queue. If the end of the queue is reached then NULL is returned. SIDE EFFECTS Returns a pointer to an item in the queue without de-queuing it. ===========================================================================*/ void *q_next ( q_type *q_ptr, /* Queue from which item is returned */ q_link_type *link_ptr /* Link whose next link is required */ ) { q_link_type *ret_link_ptr = NULL; /* Link to be returned */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); ASSERT( NULL != link_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); Q_LOCK( q_ptr ); /*------------------------------------------------------------------------- If the passed link is the last link on the queue return NULL, otherwise return the link after the passed link. -------------------------------------------------------------------------*/ if( link_ptr != q_ptr->tail_link_ptr ) { ret_link_ptr = link_ptr->next_link_ptr; } Q_FREE( q_ptr ); return (void *)ret_link_ptr; } /* q_next() */
/*=========================================================================== FUNCTION Q_PUT DESCRIPTION This function enqueues an item onto a specified queue using a specified link. The item is enqueued at the end of the queue. DEPENDENCIES The specified queue should have been previously initialized via a call to q_init. The specified link field of the item should have been prev- iously initialized via a call to q_link. RETURN VALUE None. SIDE EFFECTS The specified item is placed at the tail of the specified queue. ===========================================================================*/ void q_put ( q_type *q_ptr, /* Queue on which item is to be queued. */ q_link_type *link_ptr /* Link to use for queueing item. */ ) { /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); ASSERT( NULL != link_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); Q_LOCK( q_ptr ); /*------------------------------------------------------------------------- link_ptr is made to point to the queue's head_link, the queue's tail_link_ptr and the last link are made to point to link_ptr which then becomes the last link on the queue. Increment count of items on queue. -------------------------------------------------------------------------*/ link_ptr->next_link_ptr = &q_ptr->head_link; q_ptr->tail_link_ptr = q_ptr->tail_link_ptr->next_link_ptr = link_ptr; q_ptr->link_cnt++; Q_FREE( q_ptr ); return; } /* q_put() */
/*=========================================================================== FUNCTION Q_LAST_GET DESCRIPTION This function removes an item from the tail of a specified queue and returns it's link. DEPENDENCIES The specified queue should have been initialized previously via a call to q_init. RETURN VALUE The link of the last item in the queue. A NULL is returned if there is no item on the queue. SIDE EFFECTS The tail item is removed from the specified queue. ===========================================================================*/ void *q_last_get ( q_type *q_ptr /* Queue from which the item is returned */ ) { q_link_type *prev_link_ptr = NULL; /* Predecessor to the last link */ q_link_type *ret_link_ptr = NULL; /* Link to be returned */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); Q_LOCK( q_ptr ); /*------------------------------------------------------------------------- Check if there are any items on the queue -------------------------------------------------------------------------*/ if( &q_ptr->head_link != q_ptr->tail_link_ptr ) { /*----------------------------------------------------------------------- Get the last link and it's predecessor on the queue. Remove the last item from the queue. The ASSERT fires if the link is not on the queue and QUEUE_STRICT_CHECK is turned on. -----------------------------------------------------------------------*/ ret_link_ptr = q_ptr->tail_link_ptr; prev_link_ptr = q_prev( q_ptr, ret_link_ptr ); QUEUE_ASSERT( NULL != ret_link_ptr ); ret_link_ptr->next_link_ptr = NULL; /*----------------------------------------------------------------------- If this was the only element then set prev_link_ptr to the head_link of the queue. -----------------------------------------------------------------------*/ if( NULL == prev_link_ptr ) { prev_link_ptr = &q_ptr->head_link; } /*----------------------------------------------------------------------- Make the last link's predecessor the last link in the queue. Decrement item count. -----------------------------------------------------------------------*/ prev_link_ptr->next_link_ptr = &q_ptr->head_link; q_ptr->tail_link_ptr = prev_link_ptr; q_ptr->link_cnt--; } Q_FREE( q_ptr ); return (void *)ret_link_ptr; } /* q_last_get() */
/*=========================================================================== FUNCTION Q_INSERT DESCRIPTION This function inserts a specified item insert_link_ptr) before another specified item (next_link_ptr) on a specified queue (q_ptr). DEPENDENCIES The specified queue should have been initialized previously via a call to q_init; insert_link_ptr and next_link_ptr should have been initialized via calls to q_link. RETURN VALUE None. SIDE EFFECTS insert_link_ptr's associated item is inserted before next_link_ptr's item. ===========================================================================*/ void q_insert ( q_type *q_ptr, /* Pointer to the queue */ q_link_type *insert_link_ptr, /* Pointer to link to be inserted */ q_link_type *next_link_ptr /* This comes after insert_link_ptr */ ) { q_link_type *prev_link_ptr = NULL; /* Link before next_link_ptr */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); ASSERT( NULL != insert_link_ptr ); ASSERT( NULL != next_link_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); /*------------------------------------------------------------------------- If the next_link_ptr is the same as the head_link ASSERT. -------------------------------------------------------------------------*/ QUEUE_ASSERT( next_link_ptr != &q_ptr->head_link ); Q_LOCK( q_ptr ); /*------------------------------------------------------------------------- Find the predecessor of next_link_ptr. If next_link_ptr is the first link on the queue, set the prev_link_ptr to the head_link. -------------------------------------------------------------------------*/ prev_link_ptr = q_prev( q_ptr, next_link_ptr ); if( NULL == prev_link_ptr && q_ptr->head_link.next_link_ptr == next_link_ptr ) { prev_link_ptr = &q_ptr->head_link; } /*------------------------------------------------------------------------- ASSERT if next_link_ptr was not found on the queue. Else insert insert_link_ptr before next_link_ptr. -------------------------------------------------------------------------*/ QUEUE_ASSERT( NULL != prev_link_ptr ); insert_link_ptr->next_link_ptr = next_link_ptr; prev_link_ptr->next_link_ptr = insert_link_ptr; q_ptr->link_cnt++; Q_FREE( q_ptr ); return; } /* q_insert() */
/*=========================================================================== FUNCTION Q_GET DESCRIPTION This function removes an item from the head of a specified queue and returns it's link. DEPENDENCIES The specified queue should have been initialized previously via a call to q_init. RETURN VALUE A pointer to the first item's link. If the specified queue is empty, then NULL is returned. SIDE EFFECTS The head item, if any, is removed from the specified queue. ===========================================================================*/ void *q_get ( q_type *q_ptr /* Queue from which the item is returned */ ) { q_link_type *link_ptr = NULL; /* The link to be returned */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); Q_LOCK( q_ptr ); /*------------------------------------------------------------------------- Can only get an item if the queue is non empty -------------------------------------------------------------------------*/ if( q_ptr->head_link.next_link_ptr != &q_ptr->head_link ) { /*----------------------------------------------------------------------- Get the first queued item. Make queue's head_link point to the link this item is pointing to. -----------------------------------------------------------------------*/ link_ptr = q_ptr->head_link.next_link_ptr; q_ptr->head_link.next_link_ptr = link_ptr->next_link_ptr; /*----------------------------------------------------------------------- If this is the only item then adjust queue's tail_link_ptr. -----------------------------------------------------------------------*/ if( link_ptr == q_ptr->tail_link_ptr ) { q_ptr->tail_link_ptr = link_ptr->next_link_ptr; } /*----------------------------------------------------------------------- Decrement queue count. Mark item as no longer in the queue. -----------------------------------------------------------------------*/ q_ptr->link_cnt--; link_ptr->next_link_ptr = NULL; } Q_FREE( q_ptr ); return (void *)link_ptr; } /* q_get() */
int thread_release_dead_threads (int leave_count) { thread_t *thr; int rc; long thread_killed = 0; thread_queue_t term; Q_LOCK (); if (_deadq.thq_count <= leave_count) { Q_UNLOCK (); return 0; } thread_queue_init (&term); while (_deadq.thq_count > leave_count) { thr = thread_queue_from (&_deadq); if (!thr) break; _thread_num_dead--; thread_queue_to (&term, thr); } Q_UNLOCK (); while (NULL != (thr = thread_queue_from (&term))) { thr->thr_status = TERMINATE; rc = pthread_cond_signal ((pthread_cond_t *) thr->thr_cv); CKRET (rc); thread_killed++; } #if 0 if (thread_killed) log_info ("%ld OS threads released", thread_killed); #endif return thread_killed; failed: GPF_T1("Thread restart failed"); return 0; }
void qDestroy(queueObj_t *qObj) { if(!qObj) { return; } Q_LOCK(&qObj->qMutex); NODE *node = NULL; while(qObj->qHead != NULL) { node = qObj->qHead; qObj->qHead = qObj->qHead->next; FREE(node); } qObj->qTail = qObj->qHead = 0; Q_UNLOCK(&qObj->qMutex); pthread_mutex_destroy(&qObj->qMutex); }
void qInsert(queueObj_t *qObj, void *data) { if (!qObj || !data) { return; } Q_LOCK(&qObj->qMutex); NODE *node = allocate_node(data); if (!qObj->qHead) { qObj->qHead = qObj->qTail = node; ++qObj->qCount; } else { qObj->qTail->next = node; node->prev = qObj->qTail; qObj->qTail = node; ++qObj->qCount; } Q_UNLOCK(&qObj->qMutex); }
thread_t * thread_create ( thread_init_func initial_function, unsigned long stack_size, void *initial_argument) { thread_t *thr; int rc; assert (_main_thread != NULL); if (stack_size == 0) stack_size = THREAD_STACK_SIZE; #if (SIZEOF_VOID_P == 8) stack_size *= 2; #endif #if defined (__x86_64 ) && defined (SOLARIS) /*GK: the LDAP on that platform requires that */ stack_size *= 2; #endif #ifdef HPUX_ITANIUM64 stack_size += 8 * 8192; #endif stack_size = ((stack_size / 8192) + 1) * 8192; #if defined (PTHREAD_STACK_MIN) if (stack_size < PTHREAD_STACK_MIN) { stack_size = PTHREAD_STACK_MIN; } #endif /* Any free threads with the right stack size? */ Q_LOCK (); for (thr = (thread_t *) _deadq.thq_head.thr_next; thr != (thread_t *) &_deadq.thq_head; thr = (thread_t *) thr->thr_hdr.thr_next) { /* if (thr->thr_stack_size >= stack_size) */ break; } Q_UNLOCK (); /* No free threads, create a new one */ if (thr == (thread_t *) &_deadq.thq_head) { #ifndef OLD_PTHREADS size_t os_stack_size = stack_size; #endif thr = thread_alloc (); thr->thr_initial_function = initial_function; thr->thr_initial_argument = initial_argument; thr->thr_stack_size = stack_size; if (thr->thr_cv == NULL) goto failed; #ifdef HPUX_ITANIUM64 if (stack_size > PTHREAD_STACK_MIN) { size_t s, rses; pthread_attr_getstacksize (&_thread_attr, &s); pthread_attr_getrsestacksize_np (&_thread_attr, &rses); log_error ("default rses=%d stack=%d : %m", rses,s); } #endif #ifndef OLD_PTHREADS # if defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) rc = pthread_attr_setstacksize (&_thread_attr, stack_size); if (rc) { log_error ("Failed setting the OS thread stack size to %d : %m", stack_size); } # endif #if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) if (0 == pthread_attr_getstacksize (&_thread_attr, &os_stack_size)) { if (os_stack_size > 4 * 8192) stack_size = thr->thr_stack_size = ((unsigned long) os_stack_size) - 4 * 8192; } #endif #ifdef HPUX_ITANIUM64 if (stack_size > PTHREAD_STACK_MIN) { size_t rsestack_size = stack_size / 2; rc = pthread_attr_setrsestacksize_np (&_thread_attr, rsestack_size); if (rc) { log_error ("Failed setting the OS thread 'rse' stack size to %d (plain stack size set to %d) : %m", rsestack_size, stack_size); } thr->thr_stack_size /= 2; } #endif rc = pthread_create ((pthread_t *) thr->thr_handle, &_thread_attr, _thread_boot, thr); CKRET (rc); /* rc = pthread_detach (*(pthread_t *) thr->thr_handle); */ /* CKRET (rc); */ #else /* OLD_PTHREAD */ rc = pthread_attr_setstacksize (&_thread_attr, stack_size); CKRET (rc); rc = pthread_create ((pthread_t *) thr->thr_handle, _thread_attr, _thread_boot, thr); CKRET (rc); /* rc = pthread_detach ((pthread_t *) thr->thr_handle); */ /* CKRET (rc); */ #endif _thread_num_total++; #if 0 if (DO_LOG(LOG_THR)) log_info ("THRD_0 OS threads create (%i)", _thread_num_total); #endif thread_set_priority (thr, NORMAL_PRIORITY); } else { Q_LOCK (); thread_queue_remove (&_deadq, thr); _thread_num_dead--; Q_UNLOCK (); assert (thr->thr_status == DEAD); /* Set new context for the thread and resume it */ thr->thr_initial_function = initial_function; thr->thr_initial_argument = initial_argument; thr->thr_status = RUNNABLE; rc = pthread_cond_signal ((pthread_cond_t *) thr->thr_cv); CKRET (rc); /* if (DO_LOG(LOG_THR)) log_info ("THRD_3 OS threads reuse. Info threads - total (%ld) wait (%ld) dead (%ld)", _thread_num_total, _thread_num_wait, _thread_num_dead);*/ } return thr; failed: if (thr->thr_status == RUNNABLE) { _thread_free_attributes (thr); dk_free (thr, sizeof (thread_t)); } return NULL; }
/*=========================================================================== FUNCTION Q_DELETE DESCRIPTION This function removes a specified item from a specified queue. DEPENDENCIES The specified queue should have been initialized previously via a call to q_init. The specified link should have been initialized via call to q_link. RETURN VALUE None. SIDE EFFECTS Item is deleted from the queue. ===========================================================================*/ void q_delete ( q_type *q_ptr, /* Pointer to the queue */ q_link_type *delete_link_ptr /* Pointer to link to be removed from q */ ) { q_link_type *prev_link_ptr = NULL; /* Predecessor of delete_link_ptr */ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /*------------------------------------------------------------------------- Verify parameters -------------------------------------------------------------------------*/ ASSERT( NULL != q_ptr ); ASSERT( NULL != delete_link_ptr ); /*------------------------------------------------------------------------- Check that the queue is initialized. Works if FEATURE_QUEUE_NO_STRICT_CHECK is turned off. -------------------------------------------------------------------------*/ QUEUE_CHECK_INIT( q_ptr ); /*------------------------------------------------------------------------- Check if the item to be deleted is head_link, if not then delete the item else assert. -------------------------------------------------------------------------*/ QUEUE_ASSERT( delete_link_ptr != &q_ptr->head_link ) Q_LOCK( q_ptr ); /*------------------------------------------------------------------------- Find the predecessor of the item to be deleted. -------------------------------------------------------------------------*/ prev_link_ptr = q_prev( q_ptr, delete_link_ptr ); /*------------------------------------------------------------------------- If this is the first item set prev_link_ptr to head_link. -------------------------------------------------------------------------*/ if( NULL == prev_link_ptr && q_ptr->head_link.next_link_ptr == delete_link_ptr ) { prev_link_ptr = &q_ptr->head_link; } /*------------------------------------------------------------------------- If we found the link on the queue, remove the item. -------------------------------------------------------------------------*/ if( NULL != prev_link_ptr ) { prev_link_ptr->next_link_ptr = delete_link_ptr->next_link_ptr; /*----------------------------------------------------------------------- If this is the last item, fix the queue's tail_link_ptr. -----------------------------------------------------------------------*/ if( delete_link_ptr == q_ptr->tail_link_ptr ) { q_ptr->tail_link_ptr = prev_link_ptr; } q_ptr->link_cnt--; delete_link_ptr->next_link_ptr = NULL; } Q_FREE( q_ptr ); return; } /* q_delete() */
int thread_select (int n, fd_set *rfds, fd_set *wfds, void *event, TVAL timeout) { thread_t *thr = current_thread; struct timeval *ptv, tv; char dummy; int rc; if (timeout == TV_INFINITE) ptv = NULL; else { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; ptv = &tv; } if (event) { thr->thr_event = event; thr->thr_event_pipe = _ev_pipes[1]; if (rfds == NULL) rfds = &thr->thr_rfds; FD_SET (_ev_pipes[0], rfds); if (_ev_pipes[0] >= n) n = _ev_pipes[0] + 1; Q_LOCK (); thread_queue_to (&_waitq, thr); Q_UNLOCK (); } _thread_num_wait++; thr->thr_status = WAITEVENT; for (;;) { if ((rc = select (n, rfds, wfds, NULL, ptv)) == -1) { switch (errno) { case EINTR: continue; default: break; } thr_errno = errno; } else thr_errno = 0; break; } thr->thr_status = RUNNING; _thread_num_wait--; if (event) { thr->thr_event = NULL; thr->thr_event_pipe = -1; if (rc > 0 && FD_ISSET (_ev_pipes[0], rfds)) { read (_ev_pipes[0], &dummy, 1); rc = 0; } Q_LOCK (); thread_queue_remove (&_waitq, thr); Q_UNLOCK (); } return rc; }
void thread_exit (int n) { thread_t *thr = current_thread; volatile int is_attached = thr->thr_attached; if (thr == _main_thread) { call_exit (n); } thr->thr_retcode = n; thr->thr_status = DEAD; if (is_attached) { thr->thr_status = TERMINATE; goto terminate; } Q_LOCK (); thread_queue_to (&_deadq, thr); _thread_num_dead++; do { int rc = pthread_cond_wait ((pthread_cond_t *) thr->thr_cv, (pthread_mutex_t*) &_q_lock->mtx_mtx); CKRET (rc); } while (thr->thr_status == DEAD); Q_UNLOCK (); if (thr->thr_status == TERMINATE) goto terminate; /* Jumps back into _thread_boot */ longjmp (thr->thr_init_context, 1); failed: thread_queue_remove (&_deadq, thr); _thread_num_dead--; Q_UNLOCK (); terminate: if (thr->thr_status == TERMINATE) { #ifndef OLD_PTHREADS pthread_detach (* (pthread_t *)thr->thr_handle); #else pthread_detach ( (pthread_t *)thr->thr_handle); #endif _thread_free_attributes (thr); dk_free ((void *) thr->thr_cv, sizeof (pthread_cond_t)); semaphore_free (thr->thr_sem); semaphore_free (thr->thr_schedule_sem); dk_free (thr->thr_handle, sizeof (pthread_t)); thr_free_alloc_cache (thr); dk_free (thr, sizeof (thread_t)); } if (!is_attached) { _thread_num_total--; pthread_exit ((void *) 1L); } }