Home | History | Annotate | Line # | Download | only in libpthread
pthread_mutex.c revision 1.1.2.1
      1 /* Copyright */
      2 
      3 #include <assert.h>
      4 #include <errno.h>
      5 #include <signal.h>
      6 #include <stdlib.h>
      7 #include <ucontext.h>
      8 #include <sys/queue.h>
      9 
     10 #include "pthread.h"
     11 #include "pthread_int.h"
     12 #include "pthread_mutex.h"
     13 
     14 
     15 
     16 
     17 int
     18 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
     19 {
     20 	pthread_mutex_t newmutex;
     21 
     22 	assert(mutex != NULL);
     23 
     24 	/* XXX No mutex attr support yet. */
     25 	if (attr != NULL)
     26 		return EINVAL;
     27 
     28 	/* Allocate. */
     29 	newmutex = pthread__malloc(sizeof(struct pthread_mutex_st));
     30 	if (newmutex == NULL)
     31 		return ENOMEM;
     32 
     33 	newmutex->ptm_magic = PT_MUTEX_MAGIC;
     34 	newmutex->ptm_owner = NULL;
     35 	SIMPLEQ_INIT(&newmutex->ptm_blocked);
     36 
     37 	*mutex = newmutex;
     38 
     39 	return 0;
     40 }
     41 
     42 
     43 int
     44 pthread_mutex_destroy(pthread_mutex_t *mutex)
     45 {
     46 
     47 	if ((mutex == NULL) || (*mutex == NULL) ||
     48 	    (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
     49 		return EINVAL;
     50 
     51 	(*mutex)->ptm_magic = PT_MUTEX_DEAD;
     52 	pthread__free(*mutex);
     53 
     54 	return 0;
     55 }
     56 
     57 
     58 int
     59 pthread_mutex_lock(pthread_mutex_t *mutex)
     60 {
     61 	pthread_t self;
     62 
     63 	if ((mutex == NULL) || (*mutex == NULL) ||
     64 	    (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
     65 		return EINVAL;
     66 
     67 	self = pthread__self();
     68 
     69 	pthread_spinlock(self, &(*mutex)->ptm_interlock);
     70 
     71 	while ((*mutex)->ptm_locked == PT_MUTEX_LOCKED) {
     72 		/* Put ourselves on the queue and go to sleep. */
     73 		SIMPLEQ_INSERT_TAIL(&(*mutex)->ptm_blocked, self, pt_sleep);
     74 
     75 		self->pt_state = PT_STATE_BLOCKED;
     76 		pthread__block(self, &(*mutex)->ptm_interlock);
     77 
     78 		/* We're back. Try again. */
     79 		pthread_spinlock(self, &(*mutex)->ptm_interlock);
     80 	}
     81 
     82 	assert((*mutex)->ptm_locked == PT_MUTEX_UNLOCKED);
     83 
     84 	/* We have the interlock; go for the real thing. */
     85 	(*mutex)->ptm_locked = PT_MUTEX_LOCKED;
     86 	(*mutex)->ptm_owner = self;
     87 
     88 	pthread_spinunlock(self, &(*mutex)->ptm_interlock);
     89 
     90 	return 0;
     91 }
     92 
     93 
     94 int
     95 pthread_mutex_trylock(pthread_mutex_t *mutex)
     96 {
     97 	pthread_t self;
     98 
     99 	if ((mutex == NULL) || (*mutex == NULL) ||
    100 	    (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
    101 		return EINVAL;
    102 
    103 	if ((*mutex)->ptm_locked == PT_MUTEX_LOCKED)
    104 		return EBUSY;
    105 
    106 	self = pthread__self();
    107 
    108 	pthread_spinlock(self, &(*mutex)->ptm_interlock);
    109 	if ((*mutex)->ptm_locked == PT_MUTEX_LOCKED) {
    110 		pthread_spinunlock(self, &(*mutex)->ptm_interlock);
    111 		return EBUSY;
    112 	}
    113 
    114 	assert((*mutex)->ptm_locked == PT_MUTEX_UNLOCKED);
    115 
    116 	/* We have the interlock; go for the real thing. */
    117 	(*mutex)->ptm_locked = PT_MUTEX_LOCKED;
    118 	(*mutex)->ptm_owner = self;
    119 
    120 	pthread_spinunlock(self, &(*mutex)->ptm_interlock);
    121 
    122 	return 0;
    123 }
    124 
    125 
    126 int
    127 pthread_mutex_unlock(pthread_mutex_t *mutex)
    128 {
    129 	pthread_t self, blocked;
    130 
    131 	if ((mutex == NULL) || (*mutex == NULL) ||
    132 	    (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
    133 		return EINVAL;
    134 
    135 	if ((*mutex)->ptm_locked == PT_MUTEX_UNLOCKED)
    136 		return EPERM; /* Not exactly the right error. */
    137 
    138 	assert((*mutex)->ptm_locked == PT_MUTEX_LOCKED);
    139 
    140 	/* One is only permitted to unlock one's own mutexes. */
    141 	self = pthread__self();
    142 	if ((*mutex)->ptm_owner != self)
    143 		return EPERM;
    144 
    145 	pthread_spinlock(self, &(*mutex)->ptm_interlock);
    146 	(*mutex)->ptm_locked = PT_MUTEX_UNLOCKED;
    147 	(*mutex)->ptm_owner = NULL;
    148 
    149 	blocked = SIMPLEQ_FIRST(&(*mutex)->ptm_blocked);
    150 	if (blocked)
    151 		SIMPLEQ_REMOVE_HEAD(&(*mutex)->ptm_blocked, blocked, pt_sleep);
    152 
    153 	pthread_spinunlock(self, &(*mutex)->ptm_interlock);
    154 
    155 	if (blocked)
    156 		pthread__sched(self, blocked);
    157 
    158 	return 0;
    159 }
    160