1 #include <minix/mthread.h> 2 #include "global.h" 3 #include "proto.h" 4 5 #ifdef MTHREAD_STRICT 6 static struct __mthread_mutex *vm_front, *vm_rear; 7 static void mthread_mutex_add(mthread_mutex_t *m); 8 static void mthread_mutex_remove(mthread_mutex_t *m); 9 #else 10 # define mthread_mutex_add(m) ((*m)->mm_magic = MTHREAD_INIT_MAGIC) 11 # define mthread_mutex_remove(m) ((*m)->mm_magic = MTHREAD_NOT_INUSE) 12 #endif 13 14 /*===========================================================================* 15 * mthread_init_valid_mutexes * 16 *===========================================================================*/ 17 void mthread_init_valid_mutexes(void) 18 { 19 #ifdef MTHREAD_STRICT 20 /* Initialize list of valid mutexes */ 21 vm_front = vm_rear = NULL; 22 #endif 23 } 24 25 26 /*===========================================================================* 27 * mthread_mutex_add * 28 *===========================================================================*/ 29 #ifdef MTHREAD_STRICT 30 static void mthread_mutex_add(m) 31 mthread_mutex_t *m; 32 { 33 /* Add mutex to list of valid, initialized mutexes */ 34 35 if (vm_front == NULL) { /* Empty list */ 36 vm_front = *m; 37 (*m)->mm_prev = NULL; 38 } else { 39 vm_rear->mm_next = *m; 40 (*m)->mm_prev = vm_rear; 41 } 42 43 (*m)->mm_next = NULL; 44 vm_rear = *m; 45 } 46 #endif 47 48 /*===========================================================================* 49 * mthread_mutex_destroy * 50 *===========================================================================*/ 51 int mthread_mutex_destroy(mutex) 52 mthread_mutex_t *mutex; 53 { 54 /* Invalidate mutex and deallocate resources. */ 55 56 mthread_thread_t t; 57 mthread_tcb_t *tcb; 58 59 if (mutex == NULL) 60 return(EINVAL); 61 62 if (!mthread_mutex_valid(mutex)) 63 return(EINVAL); 64 else if ((*mutex)->mm_owner != NO_THREAD) 65 return(EBUSY); 66 67 /* Check if this mutex is not associated with a condition */ 68 for (t = (mthread_thread_t) 0; t < no_threads; t++) { 69 tcb = mthread_find_tcb(t); 70 if (tcb->m_state == MS_CONDITION) { 71 if (tcb->m_cond != NULL && tcb->m_cond->mc_mutex == *mutex) 72 return(EBUSY); 73 } 74 } 75 76 /* Not in use; invalidate it */ 77 mthread_mutex_remove(mutex); 78 free(*mutex); 79 *mutex = NULL; 80 81 return(0); 82 } 83 84 85 /*===========================================================================* 86 * mthread_mutex_init * 87 *===========================================================================*/ 88 int mthread_mutex_init(mutex, mattr) 89 mthread_mutex_t *mutex; /* Mutex that is to be initialized */ 90 mthread_mutexattr_t *mattr; /* Mutex attribute */ 91 { 92 /* Initialize the mutex to a known state. Attributes are not supported */ 93 94 struct __mthread_mutex *m; 95 96 if (mutex == NULL) 97 return(EAGAIN); 98 else if (mattr != NULL) 99 return(ENOSYS); 100 #ifdef MTHREAD_STRICT 101 else if (mthread_mutex_valid(mutex)) 102 return(EBUSY); 103 #endif 104 else if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL) 105 return(ENOMEM); 106 107 mthread_queue_init(&m->mm_queue); 108 m->mm_owner = NO_THREAD; 109 *mutex = (mthread_mutex_t) m; 110 mthread_mutex_add(mutex); /* Validate mutex; mutex now in use */ 111 112 return(0); 113 } 114 115 /*===========================================================================* 116 * mthread_mutex_lock * 117 *===========================================================================*/ 118 int mthread_mutex_lock(mutex) 119 mthread_mutex_t *mutex; /* Mutex that is to be locked */ 120 { 121 /* Try to lock this mutex. If already locked, append the current thread to 122 * FIFO queue associated with this mutex and suspend the thread. */ 123 124 struct __mthread_mutex *m; 125 126 if (mutex == NULL) 127 return(EINVAL); 128 129 m = (struct __mthread_mutex *) *mutex; 130 if (!mthread_mutex_valid(&m)) 131 return(EINVAL); 132 else if (m->mm_owner == NO_THREAD) { /* Not locked */ 133 m->mm_owner = current_thread; 134 } else if (m->mm_owner == current_thread) { 135 return(EDEADLK); 136 } else { 137 mthread_queue_add(&m->mm_queue, current_thread); 138 mthread_suspend(MS_MUTEX); 139 } 140 141 /* When we get here we acquired the lock. */ 142 return(0); 143 } 144 145 146 /*===========================================================================* 147 * mthread_mutex_remove * 148 *===========================================================================*/ 149 #ifdef MTHREAD_STRICT 150 static void mthread_mutex_remove(m) 151 mthread_mutex_t *m; 152 { 153 /* Remove mutex from list of valid, initialized mutexes */ 154 155 if ((*m)->mm_prev == NULL) 156 vm_front = (*m)->mm_next; 157 else 158 (*m)->mm_prev->mm_next = (*m)->mm_next; 159 160 if ((*m)->mm_next == NULL) 161 vm_rear = (*m)->mm_prev; 162 else 163 (*m)->mm_next->mm_prev = (*m)->mm_prev; 164 } 165 #endif 166 167 /*===========================================================================* 168 * mthread_mutex_trylock * 169 *===========================================================================*/ 170 int mthread_mutex_trylock(mutex) 171 mthread_mutex_t *mutex; /* Mutex that is to be locked */ 172 { 173 /* Try to lock this mutex and return OK. If already locked, return error. */ 174 175 struct __mthread_mutex *m; 176 177 if (mutex == NULL) 178 return(EINVAL); 179 180 m = (struct __mthread_mutex *) *mutex; 181 if (!mthread_mutex_valid(&m)) 182 return(EINVAL); 183 else if (m->mm_owner == current_thread) 184 return(EDEADLK); 185 else if (m->mm_owner == NO_THREAD) { 186 m->mm_owner = current_thread; 187 return(0); 188 } 189 190 return(EBUSY); 191 } 192 193 194 /*===========================================================================* 195 * mthread_mutex_unlock * 196 *===========================================================================*/ 197 int mthread_mutex_unlock(mutex) 198 mthread_mutex_t *mutex; /* Mutex that is to be unlocked */ 199 { 200 /* Unlock a previously locked mutex. If there is a pending lock for this mutex 201 * by another thread, mark that thread runnable. */ 202 203 struct __mthread_mutex *m; 204 205 if (mutex == NULL) 206 return(EINVAL); 207 208 m = (struct __mthread_mutex *) *mutex; 209 if (!mthread_mutex_valid(&m)) 210 return(EINVAL); 211 else if (m->mm_owner != current_thread) 212 return(EPERM); /* Can't unlock a mutex locked by another thread. */ 213 214 m->mm_owner = mthread_queue_remove(&m->mm_queue); 215 if (m->mm_owner != NO_THREAD) mthread_unsuspend(m->mm_owner); 216 return(0); 217 } 218 219 220 /*===========================================================================* 221 * mthread_mutex_valid * 222 *===========================================================================*/ 223 #ifdef MTHREAD_STRICT 224 int mthread_mutex_valid(m) 225 mthread_mutex_t *m; 226 { 227 /* Check to see if mutex is on the list of valid mutexes */ 228 struct __mthread_mutex *loopitem; 229 230 loopitem = vm_front; 231 232 while (loopitem != NULL) { 233 if (loopitem == *m) 234 return(1); 235 236 loopitem = loopitem->mm_next; 237 } 238 239 return(0); 240 } 241 #endif 242 243 /*===========================================================================* 244 * mthread_mutex_verify * 245 *===========================================================================*/ 246 #ifdef MDEBUG 247 int mthread_mutex_verify(void) 248 { 249 /* Return true when no mutexes are in use */ 250 int r = 1; 251 struct __mthread_mutex *loopitem; 252 253 #ifdef MTHREAD_STRICT 254 loopitem = vm_front; 255 256 while (loopitem != NULL) { 257 printf("mutex corruption: owner: %d\n", loopitem->mm_owner); 258 loopitem = loopitem->mm_next; 259 r = 0; 260 } 261 #endif 262 263 return(r); 264 } 265 #endif 266