mutex.c 6.91 KB
Newer Older
Michael Schmid committed
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
* Copyright (c) 2014-2016, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
Michael Schmid committed
26 27 28 29 30 31 32 33 34 35

#include <embb/base/c/mutex.h>
#include <embb/base/c/thread.h>
#include <assert.h>

#include <embb/base/c/internal/unused.h>

#ifdef EMBB_PLATFORM_THREADING_WINTHREADS

int embb_mutex_init(embb_mutex_t* mutex, int type) {
36 37 38 39 40 41 42
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	/* Critical sections in Windows are always recursive */
	InitializeCriticalSection(mutex);
	EMBB_UNUSED(type);
	return EMBB_SUCCESS;
Michael Schmid committed
43 44 45
}

int embb_mutex_lock(embb_mutex_t* mutex) {
46 47 48 49 50
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	EnterCriticalSection(mutex);
	return EMBB_SUCCESS;
Michael Schmid committed
51 52 53
}

int embb_mutex_try_lock(embb_mutex_t* mutex) {
54 55 56 57 58 59 60
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	BOOL success;
	success = TryEnterCriticalSection(mutex);
	if (success == FALSE) return EMBB_ERROR;
	return EMBB_SUCCESS;
Michael Schmid committed
61 62 63
}

int embb_mutex_unlock(embb_mutex_t* mutex) {
64 65 66 67 68
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	LeaveCriticalSection(mutex);
	return EMBB_SUCCESS;
Michael Schmid committed
69 70 71
}

void embb_mutex_destroy(embb_mutex_t* mutex) {
72 73
	assert(NULL != mutex);
	DeleteCriticalSection(mutex);
Michael Schmid committed
74 75 76 77 78 79 80
}

#endif /* EMBB_PLATFORM_THREADING_WINTHREADS */

#ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS

int embb_mutex_init(embb_mutex_t* mutex, int type) {
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	if (type == EMBB_MUTEX_PLAIN) {
		if (pthread_mutex_init(mutex, NULL) != 0) return EMBB_ERROR;
	} else {
		assert(type == EMBB_MUTEX_RECURSIVE);
		pthread_mutexattr_t attributes;
		if (pthread_mutexattr_init(&attributes) != 0) return EMBB_ERROR;
		if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) {
			pthread_mutexattr_destroy(&attributes);
			return EMBB_ERROR;
		}
		if (pthread_mutex_init(mutex, &attributes) != 0) {
			pthread_mutexattr_destroy(&attributes);
			return EMBB_ERROR;
		}
		if (pthread_mutexattr_destroy(&attributes) != 0) return EMBB_ERROR;
	}
	return EMBB_SUCCESS;
Michael Schmid committed
101 102 103
}

int embb_mutex_lock(embb_mutex_t* mutex) {
104 105 106 107 108 109 110 111
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	int result = pthread_mutex_lock(mutex);
	if (result != 0) {
		return EMBB_ERROR;
	}
	return EMBB_SUCCESS;
Michael Schmid committed
112 113 114
}

int embb_mutex_try_lock(embb_mutex_t* mutex) {
115 116 117 118 119 120 121 122 123 124 125
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	int result = pthread_mutex_trylock(mutex);
	if (result == 0) {
		return EMBB_SUCCESS;
	}
	if (result == EBUSY) {
		return EMBB_BUSY;
	}
	return EMBB_ERROR;
Michael Schmid committed
126 127 128
}

int embb_mutex_unlock(embb_mutex_t* mutex) {
129 130 131 132 133 134 135 136
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	int result = pthread_mutex_unlock(mutex);
	if (result != 0) {
		return EMBB_ERROR;
	}
	return EMBB_SUCCESS;
Michael Schmid committed
137 138 139
}

void embb_mutex_destroy(embb_mutex_t* mutex) {
140 141
	assert(NULL != mutex);
	pthread_mutex_destroy(mutex);
Michael Schmid committed
142 143 144 145
}

#endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */

146 147 148 149 150 151 152 153 154 155 156 157

#ifdef EMBB_PLATFORM_THREADING_RTOSTASKS

#include <FreeRTOS/semphr.h>
#include <FreeRTOS/portmacro.h>

int embb_mutex_init(embb_mutex_t* mutex, int type) {
	if (NULL == mutex) {
		return EMBB_ERROR;
	}

	/*
158 159 160 161 162 163 164
	 * scm34681:
	 * Type of mutex cannot be determined from SemaphoreHandle_t,
	 * but mutex gets locked with two different functions. 
	 * ==> only recursive mutexes are used. 
	 * Check Queue_t for type checking. Queue_t not defined in queue.h
	 * but queue.c...
	 */
165
	/*if(type == EMBB_MUTEX_PLAIN) {
Michael Schmid committed
166
		*mutex = xSemaphoreCreateMutex();
167 168 169
	}
	else {
		assert(type == EMBB_MUTEX_RECURSIVE);*/
Michael Schmid committed
170
		*mutex = xSemaphoreCreateRecursiveMutex();
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
	/*}*/
	
	EMBB_UNUSED(type);
	
	if(mutex == NULL) {
		return EMBB_ERROR;
	}
	
	return EMBB_SUCCESS;
}

int embb_mutex_lock(embb_mutex_t* mutex) {
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
Michael Schmid committed
186
	int result = xSemaphoreTakeRecursive(*mutex, portMAX_DELAY);
187 188 189 190 191 192 193 194 195
	if (result != 1) return EMBB_ERROR;
	return EMBB_SUCCESS;
}

int embb_mutex_try_lock(embb_mutex_t* mutex) {
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
	
Michael Schmid committed
196
	int result = xSemaphoreTakeRecursive(*mutex, 0);
197 198 199 200 201 202 203 204
	if (result != 1) return EMBB_ERROR;
	return EMBB_SUCCESS;
}

int embb_mutex_unlock(embb_mutex_t* mutex) {
	if (NULL == mutex) {
		return EMBB_ERROR;
	}
Michael Schmid committed
205
	int result = xSemaphoreGiveRecursive(*mutex);
206 207 208 209 210 211
	if(result != 1) return EMBB_ERROR;
	return EMBB_SUCCESS;
}

void embb_mutex_destroy(embb_mutex_t* mutex) {
	assert(NULL != mutex);
Michael Schmid committed
212
	vSemaphoreDelete(*mutex);
213 214 215 216 217
}


#endif /* EMBB_PLATFORM_THREADING_RTOSTASKS */

Michael Schmid committed
218
int embb_spin_init(embb_spinlock_t* spinlock) {
219 220 221 222 223 224 225
	if (NULL == spinlock) {
		return EMBB_ERROR;
	}
	// For now, store the initial value. In the future will use atomic init
	// function (as soon as available).
	embb_atomic_store_int(&spinlock->atomic_spin_variable_, 0);
	return EMBB_SUCCESS;
Michael Schmid committed
226 227 228
}

int embb_spin_lock(embb_spinlock_t* spinlock) {
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	if (NULL == spinlock) {
		return EMBB_ERROR;
	}
	int expected = 0;
	int spins = 1;

	// try to swap the
	while (0 == embb_atomic_compare_and_swap_int(
	&spinlock->atomic_spin_variable_, &expected, 1)) {
		if (0 == (spins & 1023)) {
			embb_thread_yield();
		}
		spins++;
		// reset expected, as CAS might change it...
		expected = 0;
	}
	return EMBB_SUCCESS;
Michael Schmid committed
246 247 248
}

int embb_spin_try_lock(embb_spinlock_t* spinlock,
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
unsigned int max_number_spins) {
	if (NULL == spinlock) {
		return EMBB_ERROR;
	}
	if (max_number_spins == 0)
	return EMBB_BUSY;

	int expected = 0;
	while (0 == embb_atomic_compare_and_swap_int(
	&spinlock->atomic_spin_variable_,
	&expected, 1)) {
		max_number_spins--;
		if (0 == max_number_spins) {
			return EMBB_BUSY;
		}
		expected = 0;
	}

	return EMBB_SUCCESS;
Michael Schmid committed
268 269 270
}

int embb_spin_unlock(embb_spinlock_t* spinlock) {
271 272 273 274 275 276 277
	if (NULL == spinlock) {
		return EMBB_ERROR;
	}
	int expected = 1;
	return embb_atomic_compare_and_swap_int(&spinlock->atomic_spin_variable_,
	&expected, 0) ?
	EMBB_SUCCESS : EMBB_ERROR;
Michael Schmid committed
278 279 280
}

void embb_spin_destroy(embb_spinlock_t* spinlock) {
281 282 283 284
	assert(NULL != spinlock);
	// for now, doing nothing here... in future, will call the respective
	// destroy function for atomics...
	EMBB_UNUSED(spinlock);
Michael Schmid committed
285
}