mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +00:00 
			
		
		
		
	LibPthread: Implement condition variables
This feels like a pretty naive implementation, but I think it can work. Basically each waiter creates an object on its stack that is then added to a linked list inside by the pthread_cond_t. Signalling is then done by walking the list and unsetting the "waiting" flag on as many of the waiters as you like.
This commit is contained in:
		
							parent
							
								
									db2bfe14e9
								
							
						
					
					
						commit
						cc1ef6dadb
					
				
					 3 changed files with 109 additions and 2 deletions
				
			
		|  | @ -1,11 +1,13 @@ | |||
| #include <AK/Assertions.h> | ||||
| #include <AK/Atomic.h> | ||||
| #include <AK/InlineLinkedList.h> | ||||
| #include <AK/StdLibExtras.h> | ||||
| #include <Kernel/Syscall.h> | ||||
| #include <limits.h> | ||||
| #include <pthread.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/mman.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #define PTHREAD_DEBUG | ||||
|  | @ -327,4 +329,100 @@ int pthread_attr_setstacksize(pthread_attr_t* attributes, size_t stack_size) | |||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| struct WaitNode : public InlineLinkedListNode<WaitNode> { | ||||
|     bool waiting { true }; | ||||
|     WaitNode* m_next { nullptr }; | ||||
|     WaitNode* m_prev { nullptr }; | ||||
| }; | ||||
| 
 | ||||
| struct ConditionVariable { | ||||
|     InlineLinkedList<WaitNode> waiters; | ||||
|     clockid_t clock; | ||||
| }; | ||||
| 
 | ||||
| int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr) | ||||
| { | ||||
|     auto& condvar = *new ConditionVariable; | ||||
|     cond->storage = &condvar; | ||||
|     if (attr) | ||||
|         condvar.clock = attr->clockid; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_destroy(pthread_cond_t* cond) | ||||
| { | ||||
|     delete static_cast<ConditionVariable*>(cond->storage); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) | ||||
| { | ||||
|     WaitNode node; | ||||
|     auto& condvar = *(ConditionVariable*)cond->storage; | ||||
|     condvar.waiters.append(&node); | ||||
|     while (node.waiting) { | ||||
|         pthread_mutex_unlock(mutex); | ||||
|         sched_yield(); | ||||
|         pthread_mutex_lock(mutex); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_condattr_init(pthread_condattr_t* attr) | ||||
| { | ||||
|     attr->clockid = CLOCK_MONOTONIC; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_condattr_destroy(pthread_condattr_t*) | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_condattr_setclock(pthread_condattr_t* attr, clockid_t clock) | ||||
| { | ||||
|     attr->clockid = clock; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime) | ||||
| { | ||||
|     WaitNode node; | ||||
|     auto& condvar = *(ConditionVariable*)cond->storage; | ||||
|     condvar.waiters.append(&node); | ||||
|     while (node.waiting) { | ||||
|         struct timespec now; | ||||
|         if (clock_gettime(condvar.clock, &now) < 0) | ||||
|             return -1; | ||||
|         if ((abstime->tv_sec < now.tv_sec) || (abstime->tv_sec == now.tv_sec && abstime->tv_nsec <= now.tv_nsec)) { | ||||
|             errno = ETIMEDOUT; | ||||
|             return -1; | ||||
|         } | ||||
|         pthread_mutex_unlock(mutex); | ||||
|         sched_yield(); | ||||
|         pthread_mutex_lock(mutex); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_signal(pthread_cond_t* cond) | ||||
| { | ||||
|     auto& condvar = *(ConditionVariable*)cond->storage; | ||||
|     if (condvar.waiters.is_empty()) | ||||
|         return 0; | ||||
|     auto* node = condvar.waiters.remove_head(); | ||||
|     node->waiting = false; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int pthread_cond_broadcast(pthread_cond_t* cond) | ||||
| { | ||||
|     auto& condvar = *(ConditionVariable*)cond->storage; | ||||
|     while (!condvar.waiters.is_empty()) { | ||||
|         auto* node = condvar.waiters.remove_head(); | ||||
|         node->waiting = false; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling