Edit

IABSD.fr/src/lib/libc/thread/rthread_cond.c

Branch :

  • Show log

    Commit

  • Author : mpi
    Date : 2019-01-29 17:40:26
    Hash : f3cfced6
    Message : There's no point in asserting that a pointer is not NULL before dereferencing it. ok kettenis@, visa@

  • lib/libc/thread/rthread_cond.c
  • /*	$OpenBSD: rthread_cond.c,v 1.5 2019/01/29 17:40:26 mpi Exp $ */
    /*
     * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
     * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <errno.h>
    #include <pthread.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include "rthread.h"
    #include "cancel.h"
    #include "synch.h"
    
    int
    pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr)
    {
    	pthread_cond_t cond;
    
    	cond = calloc(1, sizeof(*cond));
    	if (cond == NULL)
    		return (ENOMEM);
    
    	if (attr == NULL)
    		cond->clock = CLOCK_REALTIME;
    	else
    		cond->clock = (*attr)->ca_clock;
    	*condp = cond;
    
    	return (0);
    }
    DEF_STRONG(pthread_cond_init);
    
    int
    pthread_cond_destroy(pthread_cond_t *condp)
    {
    	pthread_cond_t cond;
    
    	cond = *condp;
    
    	if (cond != NULL) {
    		if (cond->mutex != NULL) {
    #define MSG "pthread_cond_destroy on condvar with waiters!\n"
    			write(2, MSG, sizeof(MSG) - 1);
    #undef MSG
    			return (EBUSY);
    		}
    		free(cond);
    	}
    	*condp = NULL;
    
    	return (0);
    }
    
    int
    _rthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t *mutexp,
        const struct timespec *abs)
    {
    	struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp;
    	struct tib *tib = TIB_GET();
    	pthread_t self = tib->tib_thread;
    	int error, rv = 0, canceled = 0, mutex_count = 0;
    	clockid_t clock = cond->clock;
    	int seq = cond->seq;
    	PREP_CANCEL_POINT(tib);
    
    	_rthread_debug(5, "%p: cond_timed %p,%p (%p)\n", self,
    	    (void *)cond, (void *)mutex, (void *)mutex->owner);
    
    	ENTER_DELAYED_CANCEL_POINT(tib, self);
    
    #if notyet
    	/* mark the condvar as being associated with this mutex */
    	if (cond->mutex == NULL)
    		atomic_cas_ptr(&cond->mutex, NULL, mutex);
    
    	if (cond->mutex != mutex) {
    		LEAVE_CANCEL_POINT_INNER(tib, 1);
    		return (EINVAL);
    	}
    #endif
    
    	/* snag the count in case this is a recursive mutex */
    	if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
    		mutex_count = mutex->count;
    
    	pthread_mutex_unlock(mutexp);
    
    	do {
    		/* If ``seq'' wraps you deserve to lose a signal. */
    		error = _twait(&cond->seq, seq, clock, abs);
    		/*
    		* If we took a normal signal (not from cancellation) then
    		* we should just go back to sleep without changing state
    		* (timeouts, etc).
    		*/
    	} while ((error == EINTR) &&
    	   (tib->tib_canceled == 0 || (tib->tib_cantcancel & CANCEL_DISABLED)));
    
    	/* if timeout or canceled, make note of that */
    	if (error == ETIMEDOUT)
    		rv = ETIMEDOUT;
    	else if (error == EINTR)
    		canceled = 1;
    
    	pthread_mutex_lock(mutexp);
    
    	/* restore the mutex's count */
    	if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
    		mutex->count = mutex_count;
    
    	LEAVE_CANCEL_POINT_INNER(tib, canceled);
    
    	return rv;
    }
    
    int
    pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp,
        const struct timespec *abs)
    {
    	pthread_cond_t cond;
    	int error;
    
    	if (*condp == NULL) {
    		if ((error = pthread_cond_init(condp, NULL)))
    			return (error);
    	}
    
    	cond = *condp;
    	if (abs == NULL || abs->tv_sec < 0 || abs->tv_nsec < 0 ||
    	    abs->tv_nsec >= 1000000000)
    		return (EINVAL);
    
    	return (_rthread_cond_timedwait(cond, mutexp, abs));
    }
    
    int
    pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp)
    {
    	pthread_cond_t cond;
    	int error;
    
    	if (*condp == NULL) {
    		if ((error = pthread_cond_init(condp, NULL)))
    			return (error);
    	}
    
    	cond = *condp;
    	return (_rthread_cond_timedwait(cond, mutexp, NULL));
    }
    
    int
    pthread_cond_signal(pthread_cond_t *condp)
    {
    	pthread_cond_t cond;
    	int count;
    
    	if (*condp == NULL)
    		return (0);
    
    	cond = *condp;
    
    	atomic_inc_int(&cond->seq);
    	count = _wake(&cond->seq, 1);
    
    	_rthread_debug(5, "%p: cond_signal %p, %d awaken\n", pthread_self(),
    	    (void *)cond, count);
    
    	return (0);
    }
    
    int
    pthread_cond_broadcast(pthread_cond_t *condp)
    {
    	pthread_cond_t cond;
    	int count;
    
    	if (*condp == NULL)
    		return (0);
    
    	cond = *condp;
    
    	atomic_inc_int(&cond->seq);
    #if notyet
    	count = _requeue(&cond->seq, 1, INT_MAX, &cond->mutex->lock);
    #else
    	count = _wake(&cond->seq, INT_MAX);
    #endif
    
    	_rthread_debug(5, "%p: cond_broadcast %p, %d awaken\n", pthread_self(),
    	    (void *)cond, count);
    
    	return (0);
    }