2 // Threading primitives for CUPS.
4 // Copyright © 2020-2024 by OpenPrinting.
5 // Copyright © 2009-2018 by Apple Inc.
7 // Licensed under Apache License v2.0. See the file "LICENSE" for more
11 #include "cups-private.h"
16 // Windows threading...
24 // Private structures...
29 HANDLE h
; // Thread handle
30 void *(*func
)(void *); // Thread start function
31 void *arg
; // Argument to pass to function
32 void *retval
; // Return value from function
33 bool canceled
; // Is the thread canceled?
34 jmp_buf jumpbuf
; // Jump buffer for error recovery
42 static cups_thread_t
win32_self(void);
43 static void win32_testcancel(void);
44 static DWORD
win32_tls(void);
45 static int win32_wrapper(cups_thread_t thread
);
49 // 'cupsCondBroadcast()' - Wake up waiting threads.
53 cupsCondBroadcast(cups_cond_t
*cond
) // I - Condition variable
56 WakeAllConditionVariable(cond
);
61 // 'cupsCondDestroy()' - Destroy a condition variable.
65 cupsCondDestroy(cups_cond_t
*cond
) // I - Condition variable
72 // 'cupsCondInit()' - Initialize a condition variable.
76 cupsCondInit(cups_cond_t
*cond
) // I - Condition variable
79 InitializeConditionVariable(cond
);
84 // 'cupsCondWait()' - Wait for a condition with optional timeout.
88 cupsCondWait(cups_cond_t
*cond
, // I - Condition
89 cups_mutex_t
*mutex
, // I - Mutex
90 double timeout
) // I - Timeout in seconds (`0` or negative for none)
97 SleepConditionVariableCS(cond
, mutex
, (int)(1000.0 * timeout
));
99 SleepConditionVariableCS(cond
, mutex
, INFINITE
);
105 // 'cupsMutexDestroy()' - Destroy a mutex.
109 cupsMutexDestroy(cups_mutex_t
*mutex
) // I - Mutex
116 // 'cupsMutexInit()' - Initialize a mutex.
120 cupsMutexInit(cups_mutex_t
*mutex
) // I - Mutex
123 InitializeCriticalSection(mutex
);
128 // 'cupsMutexLock()' - Lock a mutex.
132 cupsMutexLock(cups_mutex_t
*mutex
) // I - Mutex
135 EnterCriticalSection(mutex
);
140 // 'cupsMutexUnlock()' - Unlock a mutex.
144 cupsMutexUnlock(cups_mutex_t
*mutex
) // I - Mutex
147 LeaveCriticalSection(mutex
);
152 // 'cupsRWDestroy()' - Destroy a reader/writer lock.
156 cupsRWDestroy(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
163 // 'cupsRWInit()' - Initialize a reader/writer lock.
167 cupsRWInit(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
170 InitializeSRWLock(rwlock
);
175 // 'cupsRWLockRead()' - Acquire a reader/writer lock for reading.
179 cupsRWLockRead(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
182 AcquireSRWLockShared(rwlock
);
187 // 'cupsRWLockWrite()' - Acquire a reader/writer lock for writing.
191 cupsRWLockWrite(cups_rwlock_t
*rwlock
)// I - Reader/writer lock
194 AcquireSRWLockExclusive(rwlock
);
199 // 'cupsRWUnlock()' - Release a reader/writer lock.
203 cupsRWUnlock(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
207 void *val
= *(void **)rwlock
;// Lock value
209 if (val
== (void *)1)
210 ReleaseSRWLockExclusive(rwlock
);
212 ReleaseSRWLockShared(rwlock
);
218 // 'cupsThreadCancel()' - Cancel (kill) a thread.
222 cupsThreadCancel(cups_thread_t thread
)// I - Thread ID
225 thread
->canceled
= true;
230 // 'cupsThreadCreate()' - Create a thread.
233 cups_thread_t
// O - Thread ID or `CUPS_THREAD_INVALID` on failure
235 cups_thread_func_t func
, // I - Entry point
236 void *arg
) // I - Entry point context
238 cups_thread_t thread
; // Thread data
242 return (CUPS_THREAD_INVALID
);
244 if ((thread
= (cups_thread_t
)calloc(1, sizeof(struct _cups_thread_s
))) == NULL
)
245 return (CUPS_THREAD_INVALID
);
249 thread
->h
= (HANDLE
)_beginthreadex(NULL
, 0, (LPTHREAD_START_ROUTINE
)win32_wrapper
, thread
, 0, NULL
);
251 if (thread
->h
== 0 || thread
->h
== (HANDLE
)-1)
254 return (CUPS_THREAD_INVALID
);
262 // 'cupsThreadDetach()' - Tell the OS that the thread is running independently.
266 cupsThreadDetach(cups_thread_t thread
)// I - Thread ID
270 CloseHandle(thread
->h
);
277 // 'cupsThreadWait()' - Wait for a thread to exit.
280 void * // O - Return value
281 cupsThreadWait(cups_thread_t thread
) // I - Thread ID
283 void *retval
; // Return value
293 WaitForSingleObject(thread
->h
, INFINITE
);
294 CloseHandle(thread
->h
);
297 retval
= thread
->retval
;
306 // 'win32_self()' - Return the current thread.
309 static cups_thread_t
// O - Thread
312 cups_thread_t thread
; // Thread
315 if ((thread
= TlsGetValue(win32_tls())) == NULL
)
317 // Main thread, so create the info we need...
318 if ((thread
= (cups_thread_t
)calloc(1, sizeof(struct _cups_thread_s
))) != NULL
)
320 thread
->h
= GetCurrentThread();
321 TlsSetValue(win32_tls(), thread
);
323 if (setjmp(thread
->jumpbuf
))
338 // 'win32_testcancel()' - Mark a safe cancellation point.
342 win32_testcancel(void)
344 cups_thread_t thread
; // Current thread
347 // Go to the thread's exit handler if we've been canceled...
348 if ((thread
= win32_self()) != NULL
&& thread
->canceled
)
349 longjmp(thread
->jumpbuf
, 1);
354 // 'win32_tls()' - Get the thread local storage key.
357 static DWORD
// O - Key
360 static DWORD tls
= 0; // Thread local storage key
361 static CRITICAL_SECTION tls_mutex
= { (void*)-1, -1, 0, 0, 0, 0 };
362 // Lock for thread local storage access
365 EnterCriticalSection(&tls_mutex
);
368 if ((tls
= TlsAlloc()) == TLS_OUT_OF_INDEXES
)
371 LeaveCriticalSection(&tls_mutex
);
378 // 'win32_wrapper()' - Wrapper function for a POSIX thread.
381 static int // O - Exit status
382 win32_wrapper(cups_thread_t thread
) // I - Thread
384 TlsSetValue(win32_tls(), thread
);
386 if (!setjmp(thread
->jumpbuf
))
388 // Call function in thread...
389 thread
->retval
= (thread
->func
)(thread
->arg
);
393 while (thread
->h
== (HANDLE
)-1)
395 // win32_create hasn't finished initializing the handle...
400 // Free if detached...
410 // POSIX threading...
414 // 'cupsCondBroadcast()' - Wake up waiting threads.
418 cupsCondBroadcast(cups_cond_t
*cond
) // I - Condition
420 pthread_cond_broadcast(cond
);
425 // 'cupsCondDestroy()' - Destroy a condition variable.
429 cupsCondDestroy(cups_cond_t
*cond
) // I - Condition
431 pthread_cond_destroy(cond
);
436 // 'cupsCondInit()' - Initialize a condition variable.
440 cupsCondInit(cups_cond_t
*cond
) // I - Condition
442 pthread_cond_init(cond
, NULL
);
447 // 'cupsCondWait()' - Wait for a condition with optional timeout.
451 cupsCondWait(cups_cond_t
*cond
, // I - Condition
452 cups_mutex_t
*mutex
, // I - Mutex
453 double timeout
) // I - Timeout in seconds (`0` or negative for none)
457 struct timespec abstime
; // Timeout
459 clock_gettime(CLOCK_REALTIME
, &abstime
);
461 abstime
.tv_sec
+= (long)timeout
;
462 abstime
.tv_nsec
+= (long)(1000000000 * (timeout
- (long)timeout
));
464 while (abstime
.tv_nsec
>= 1000000000)
466 abstime
.tv_nsec
-= 1000000000;
470 (void)pthread_cond_timedwait(cond
, mutex
, &abstime
);
473 (void)pthread_cond_wait(cond
, mutex
);
478 // 'cupsMutexDestroy()' - Destroy a mutex.
482 cupsMutexDestroy(cups_mutex_t
*mutex
) // I - Mutex
484 pthread_mutex_destroy(mutex
);
489 // 'cupsMutexInit()' - Initialize a mutex.
493 cupsMutexInit(cups_mutex_t
*mutex
) // I - Mutex
495 pthread_mutex_init(mutex
, NULL
);
500 // 'cupsMutexLock()' - Lock a mutex.
504 cupsMutexLock(cups_mutex_t
*mutex
) // I - Mutex
506 pthread_mutex_lock(mutex
);
511 // 'cupsMutexUnlock()' - Unlock a mutex.
515 cupsMutexUnlock(cups_mutex_t
*mutex
) // I - Mutex
517 pthread_mutex_unlock(mutex
);
522 // 'cupsRWDestroy()' - Destroy a reader/writer lock.
526 cupsRWDestroy(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
528 pthread_rwlock_destroy(rwlock
);
533 // 'cupsRWInit()' - Initialize a reader/writer lock.
537 cupsRWInit(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
539 pthread_rwlock_init(rwlock
, NULL
);
544 // 'cupsRWLockRead()' - Acquire a reader/writer lock for reading.
548 cupsRWLockRead(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
550 pthread_rwlock_rdlock(rwlock
);
555 // 'cupsRWLockWrite()' - Acquire a reader/writer lock for writing.
559 cupsRWLockWrite(cups_rwlock_t
*rwlock
)// I - Reader/writer lock
561 pthread_rwlock_wrlock(rwlock
);
566 // 'cupsRWUnlock()' - Release a reader/writer lock.
570 cupsRWUnlock(cups_rwlock_t
*rwlock
) // I - Reader/writer lock
572 pthread_rwlock_unlock(rwlock
);
577 // 'cupsThreadCancel()' - Cancel (kill) a thread.
581 cupsThreadCancel(cups_thread_t thread
)// I - Thread ID
583 pthread_cancel(thread
);
588 // 'cupsThreadCreate()' - Create a thread.
591 cups_thread_t
// O - Thread ID or `CUPS_THREAD_INVALID` on failure
593 cups_thread_func_t func
, // I - Entry point
594 void *arg
) // I - Entry point context
596 pthread_t thread
; // Thread
599 if (pthread_create(&thread
, NULL
, (void *(*)(void *))func
, arg
))
600 return (CUPS_THREAD_INVALID
);
607 // 'cupsThreadDetach()' - Tell the OS that the thread is running independently.
611 cupsThreadDetach(cups_thread_t thread
)// I - Thread ID
613 pthread_detach(thread
);
618 // 'cupsThreadWait()' - Wait for a thread to exit.
621 void * // O - Return value
622 cupsThreadWait(cups_thread_t thread
) // I - Thread ID
624 void *ret
; // Return value
627 if (pthread_join(thread
, &ret
))