1 /*-------------------------------------------------------------------------
2 * Copyright (C) 2000 Caldera Systems, Inc
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Caldera Systems nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA
24 * SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *-------------------------------------------------------------------------*/
32
33 /** Thread synchronization.
34 *
35 * Implementation of threading and mutex primitives.
36 *
37 * @file slp_thread.c
38 * @author John Calcote (jcalcote@novell.com)
39 * @attention Please submit patches to http://www.openslp.org
40 * @ingroup CommonCodeThread
41 */
42
43 #include "slp_types.h"
44 #include "slp_thread.h"
45 #include "slp_xmalloc.h"
46
47 /** Create a new thread of execution.
48 *
49 * While it could be argued that creating a new thread for each async
50 * request is inefficient, it's equally true that network latency and the
51 * most often practiced uses of the SLP API don't mandate the overhead of
52 * more heavy-weight constructs (e.g., thread pools) to solve this problem.
53 *
54 * @param[in] startproc - The function to run on a new thread.
55 * @param[in] arg - Context data to pass to @p startproc.
56 *
57 * @return A thread handle that may be used later by another thread to
58 * synchronize with the new thread's termination point. In pthread
59 * parlance, this attribute is called "joinable".
60 *
61 * @remarks The function address passed for @p startproc must match the
62 * following signature: void * startproc(void *), where the return value
63 * and the parameter must both be integer values the size of a pointer on
64 * the target platform.
65 */
SLPThreadCreate(SLPThreadStartProc startproc,void * arg)66 SLPThreadHandle SLPThreadCreate(SLPThreadStartProc startproc, void * arg)
67 {
68 #ifdef _WIN32
69 return (SLPThreadHandle)CreateThread(0, 0,
70 (LPTHREAD_START_ROUTINE)startproc, arg, 0, 0);
71 #else
72 pthread_t th;
73 return (SLPThreadHandle)(pthread_create(&th, 0, startproc, arg)? 0: th);
74 #endif
75 }
76
77 /** Wait for a thread to terminate.
78 *
79 * Causes the caller to wait in an efficient wait-state until the thread
80 * associated with the handle @p th terminates.
81 *
82 * @param[in] th - The thread handle to wait on.
83 *
84 * @return The thread's exit code.
85 */
SLPThreadWait(SLPThreadHandle th)86 void * SLPThreadWait(SLPThreadHandle th)
87 {
88 void * result = 0;
89 #ifdef _WIN32
90 DWORD dwres;
91 WaitForSingleObject((HANDLE)th, INFINITE);
92 if (GetExitCodeThread((HANDLE)th, &dwres))
93 result = (void *)(intptr_t)dwres;
94 CloseHandle((HANDLE)th);
95 #else
96 pthread_join((pthread_t)th, &result);
97 #endif
98 return result;
99 }
100
101 /** Create a new mutex lock.
102 *
103 * Create and return a handle to a new recursive mutex lock. Note that
104 * Windows CRITICAL_SECTION objects are recursive by default, whereas
105 * pthread mutexes have to be configured that way with an attribute.
106 *
107 * @return The new mutex's handle, or zero on failure (generally memory
108 * allocation failure causes mutex creation failure).
109 */
SLPMutexCreate(void)110 SLPMutexHandle SLPMutexCreate(void)
111 {
112 #ifdef _WIN32
113 CRITICAL_SECTION * mutex = (CRITICAL_SECTION *)xmalloc(sizeof(*mutex));
114 if (mutex != 0)
115 InitializeCriticalSection(mutex);
116 #else
117 pthread_mutex_t * mutex = 0;
118 pthread_mutexattr_t attr;
119 if (pthread_mutexattr_init(&attr) == 0)
120 {
121 #ifdef HAVE_PTHREAD_MUTEXATTR_SETTYPE
122 (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
123 #else
124 #ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP
125 (void)pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
126 #else
127 #error "Don't know how to make mutex recursive"
128 #endif /* HAVE_PTHREAD_MUTEXATTR_SETKIND_NP */
129 #endif /* HAVE_PTHREAD_MUTEXATTR_SETTYPE */
130 mutex = (pthread_mutex_t *)xmalloc(sizeof(*mutex));
131 if (mutex != 0 && pthread_mutex_init(mutex, &attr) != 0)
132 {
133 xfree(mutex);
134 mutex = 0;
135 }
136 (void)pthread_mutexattr_destroy(&attr);
137 }
138 #endif /* _WIN32 */
139 return (SLPMutexHandle)mutex;
140 }
141
142 /** Acquire a lock on a mutex.
143 *
144 * @param[in] mh - The mutex handle to be acquired.
145 */
SLPMutexAcquire(SLPMutexHandle mh)146 void SLPMutexAcquire(SLPMutexHandle mh)
147 {
148 #ifdef _WIN32
149 EnterCriticalSection((CRITICAL_SECTION *)mh);
150 #else
151 (void)pthread_mutex_lock((pthread_mutex_t *)mh);
152 #endif
153 }
154
155 /** Try to acquire a lock on a mutex.
156 *
157 * @param[in] mh - The mutex handle on which to attempt acquisition.
158 */
SLPMutexTryAcquire(SLPMutexHandle mh)159 bool SLPMutexTryAcquire(SLPMutexHandle mh)
160 {
161 #ifdef _WIN32
162 return TryEnterCriticalSection((CRITICAL_SECTION *)mh) != FALSE;
163 #else
164 return pthread_mutex_trylock((pthread_mutex_t *)mh) == 0;
165 #endif
166 }
167
168 /** Release a lock on a mutex.
169 *
170 * @param[in] mh - The mutex handle to be released.
171 */
SLPMutexRelease(SLPMutexHandle mh)172 void SLPMutexRelease(SLPMutexHandle mh)
173 {
174 #ifdef _WIN32
175 LeaveCriticalSection((CRITICAL_SECTION *)mh);
176 #else
177 (void)pthread_mutex_unlock((pthread_mutex_t *)mh);
178 #endif
179 }
180
181 /** Destroy a mutex lock.
182 *
183 * @param[in] mh - The mutex handle to be destroyed.
184 */
SLPMutexDestroy(SLPMutexHandle mh)185 void SLPMutexDestroy(SLPMutexHandle mh)
186 {
187 #ifdef _WIN32
188 DeleteCriticalSection((CRITICAL_SECTION *)mh);
189 #else
190 (void)pthread_mutex_destroy((pthread_mutex_t *)mh);
191 #endif
192 free(mh);
193 }
194
195 /*=========================================================================*/
196