1 /*
2  * Lock functions
3  *
4  * Copyright (C) 2012-2020, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25 
26 #include <errno.h>
27 
28 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
29 #include <pthread.h>
30 #endif
31 
32 #include "libcthreads_libcerror.h"
33 #include "libcthreads_lock.h"
34 #include "libcthreads_types.h"
35 
36 #if !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT )
37 
38 /* Creates a lock
39  * Make sure the value lock is referencing, is set to NULL
40  * Returns 1 if successful or -1 on error
41  */
libcthreads_lock_initialize(libcthreads_lock_t ** lock,libcerror_error_t ** error)42 int libcthreads_lock_initialize(
43      libcthreads_lock_t **lock,
44      libcerror_error_t **error )
45 {
46 	libcthreads_internal_lock_t *internal_lock = NULL;
47 	static char *function                      = "libcthreads_lock_initialize";
48 
49 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
50 	int pthread_result                         = 0;
51 #endif
52 
53 	if( lock == NULL )
54 	{
55 		libcerror_error_set(
56 		 error,
57 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59 		 "%s: invalid lock.",
60 		 function );
61 
62 		return( -1 );
63 	}
64 	if( *lock != NULL )
65 	{
66 		libcerror_error_set(
67 		 error,
68 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
69 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70 		 "%s: invalid lock value already set.",
71 		 function );
72 
73 		return( -1 );
74 	}
75 	internal_lock = memory_allocate_structure(
76 	                 libcthreads_internal_lock_t );
77 
78 	if( internal_lock == NULL )
79 	{
80 		libcerror_error_set(
81 		 error,
82 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
83 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84 		 "%s: unable to create lock.",
85 		 function );
86 
87 		goto on_error;
88 	}
89 	if( memory_set(
90 	     internal_lock,
91 	     0,
92 	     sizeof( libcthreads_internal_lock_t ) ) == NULL )
93 	{
94 		libcerror_error_set(
95 		 error,
96 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
97 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
98 		 "%s: unable to clear lock.",
99 		 function );
100 
101 		memory_free(
102 		 internal_lock );
103 
104 		return( -1 );
105 	}
106 #if defined( WINAPI )
107 	InitializeCriticalSection(
108 	 &( internal_lock->critical_section ) );
109 
110 #elif defined( HAVE_PTHREAD_H )
111 	pthread_result = pthread_mutex_init(
112 	                  &( internal_lock->mutex ),
113 	                  NULL );
114 
115 	switch( pthread_result )
116 	{
117 		case 0:
118 			break;
119 
120 		case EAGAIN:
121 			libcerror_error_set(
122 			 error,
123 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
124 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
125 			 "%s: unable to initialize mutex with error: Insufficient resources.",
126 			 function );
127 
128 			goto on_error;
129 
130 		default:
131 			libcerror_system_set_error(
132 			 error,
133 			 pthread_result,
134 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
135 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
136 			 "%s: unable to initialize mutex.",
137 			 function );
138 
139 			goto on_error;
140 	}
141 #endif
142 	*lock = (libcthreads_lock_t *) internal_lock;
143 
144 	return( 1 );
145 
146 on_error:
147 	if( internal_lock != NULL )
148 	{
149 		memory_free(
150 		 internal_lock );
151 	}
152 	return( -1 );
153 }
154 
155 /* Frees a lock
156  * Returns 1 if successful or -1 on error
157  */
libcthreads_lock_free(libcthreads_lock_t ** lock,libcerror_error_t ** error)158 int libcthreads_lock_free(
159      libcthreads_lock_t **lock,
160      libcerror_error_t **error )
161 {
162 	libcthreads_internal_lock_t *internal_lock = NULL;
163 	static char *function                      = "libcthreads_lock_free";
164 	int result                                 = 1;
165 
166 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
167 	int pthread_result                         = 0;
168 #endif
169 
170 	if( lock == NULL )
171 	{
172 		libcerror_error_set(
173 		 error,
174 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
175 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
176 		 "%s: invalid lock.",
177 		 function );
178 
179 		return( -1 );
180 	}
181 	if( *lock != NULL )
182 	{
183 		internal_lock = (libcthreads_internal_lock_t *) *lock;
184 		*lock         = NULL;
185 
186 #if defined( WINAPI )
187 		DeleteCriticalSection(
188 		 &( internal_lock->critical_section ) );
189 
190 #elif defined( HAVE_PTHREAD_H )
191 		pthread_result = pthread_mutex_destroy(
192 		                  &( internal_lock->mutex ) );
193 
194 		switch( pthread_result )
195 		{
196 			case 0:
197 				break;
198 
199 			case EAGAIN:
200 				libcerror_error_set(
201 				 error,
202 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
204 				 "%s: unable to destroy mutex with error: Insufficient resources.",
205 				 function );
206 
207 				result = -1;
208 				break;
209 
210 			case EBUSY:
211 				libcerror_error_set(
212 				 error,
213 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
214 				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
215 				 "%s: unable to destroy mutex with error: Resource busy.",
216 				 function );
217 
218 				result = -1;
219 				break;
220 
221 			default:
222 				libcerror_system_set_error(
223 				 error,
224 				 pthread_result,
225 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
226 				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
227 				 "%s: unable to destroy mutex.",
228 				 function );
229 
230 				result = -1;
231 				break;
232 		}
233 #endif
234 		memory_free(
235 		 internal_lock );
236 	}
237 	return( result );
238 }
239 
240 /* Grabs a lock
241  * Returns 1 if successful or -1 on error
242  */
libcthreads_lock_grab(const libcthreads_lock_t * lock,libcerror_error_t ** error)243 int libcthreads_lock_grab(
244      const libcthreads_lock_t *lock,
245      libcerror_error_t **error )
246 {
247 	libcthreads_internal_lock_t *internal_lock = NULL;
248 	static char *function                      = "libcthreads_lock_grab";
249 
250 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
251 	int pthread_result                         = 0;
252 #endif
253 
254 	if( lock == NULL )
255 	{
256 		libcerror_error_set(
257 		 error,
258 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
259 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
260 		 "%s: invalid lock.",
261 		 function );
262 
263 		return( -1 );
264 	}
265 	internal_lock = (libcthreads_internal_lock_t *) lock;
266 
267 #if defined( WINAPI )
268 	EnterCriticalSection(
269 	 &( internal_lock->critical_section ) );
270 
271 #elif defined( HAVE_PTHREAD_H )
272 	pthread_result = pthread_mutex_lock(
273 	                  &( internal_lock->mutex ) );
274 
275 	switch( pthread_result )
276 	{
277 		case 0:
278 			break;
279 
280 		case EAGAIN:
281 			libcerror_error_set(
282 			 error,
283 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
284 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
285 			 "%s: unable to lock mutex with error: Maximum number of locks exceeded.",
286 			 function );
287 
288 			return( -1 );
289 
290 		case EDEADLK:
291 			libcerror_error_set(
292 			 error,
293 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
294 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
295 			 "%s: unable to lock mutex with error: Deadlock condition detected.",
296 			 function );
297 
298 			return( -1 );
299 
300 		default:
301 			libcerror_system_set_error(
302 			 error,
303 			 pthread_result,
304 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
305 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
306 			 "%s: unable to lock mutex.",
307 			 function );
308 
309 			return( -1 );
310 	}
311 #endif
312 	return( 1 );
313 }
314 
315 /* Releases a lock
316  * Returns 1 if successful or -1 on error
317  */
libcthreads_lock_release(const libcthreads_lock_t * lock,libcerror_error_t ** error)318 int libcthreads_lock_release(
319      const libcthreads_lock_t *lock,
320      libcerror_error_t **error )
321 {
322 	libcthreads_internal_lock_t *internal_lock = NULL;
323 	static char *function                      = "libcthreads_lock_release";
324 
325 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
326 	int pthread_result                         = 0;
327 #endif
328 
329 	if( lock == NULL )
330 	{
331 		libcerror_error_set(
332 		 error,
333 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
334 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
335 		 "%s: invalid lock.",
336 		 function );
337 
338 		return( -1 );
339 	}
340 	internal_lock = (libcthreads_internal_lock_t *) lock;
341 
342 #if defined( WINAPI )
343 	LeaveCriticalSection(
344 	 &( internal_lock->critical_section ) );
345 
346 #elif defined( HAVE_PTHREAD_H )
347 	pthread_result = pthread_mutex_unlock(
348 	                  &( internal_lock->mutex ) );
349 
350 	switch( pthread_result )
351 	{
352 		case 0:
353 			break;
354 
355 		case EAGAIN:
356 			libcerror_error_set(
357 			 error,
358 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
359 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
360 			 "%s: unable to unlock mutex with error: Maximum number of locks exceeded.",
361 			 function );
362 
363 			return( -1 );
364 
365 		case EDEADLK:
366 			libcerror_error_set(
367 			 error,
368 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
369 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
370 			 "%s: unable to unlock mutex with error: Deadlock condition detected.",
371 			 function );
372 
373 			return( -1 );
374 
375 		default:
376 			libcerror_system_set_error(
377 			 error,
378 			 pthread_result,
379 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
380 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
381 			 "%s: unable to unlock mutex.",
382 			 function );
383 
384 			return( -1 );
385 	}
386 #endif
387 	return( 1 );
388 }
389 
390 #endif /* !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT ) */
391 
392