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