1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/posix/pthread.h>
9 
10 /**
11  * @brief Destroy semaphore.
12  *
13  * see IEEE 1003.1
14  */
sem_destroy(sem_t * semaphore)15 int sem_destroy(sem_t *semaphore)
16 {
17 	if (semaphore == NULL) {
18 		errno = EINVAL;
19 		return -1;
20 	}
21 
22 	if (k_sem_count_get(semaphore)) {
23 		errno = EBUSY;
24 		return -1;
25 	}
26 
27 	k_sem_reset(semaphore);
28 	return 0;
29 }
30 
31 /**
32  * @brief Get value of semaphore.
33  *
34  * See IEEE 1003.1
35  */
sem_getvalue(sem_t * semaphore,int * value)36 int sem_getvalue(sem_t *semaphore, int *value)
37 {
38 	if (semaphore == NULL) {
39 		errno = EINVAL;
40 		return -1;
41 	}
42 
43 	*value = (int) k_sem_count_get(semaphore);
44 
45 	return 0;
46 }
47 /**
48  * @brief Initialize semaphore.
49  *
50  * See IEEE 1003.1
51  */
sem_init(sem_t * semaphore,int pshared,unsigned int value)52 int sem_init(sem_t *semaphore, int pshared, unsigned int value)
53 {
54 	if (value > CONFIG_SEM_VALUE_MAX) {
55 		errno = EINVAL;
56 		return -1;
57 	}
58 
59 	/*
60 	 * Zephyr has no concept of process, so only thread shared
61 	 * semaphore makes sense in here.
62 	 */
63 	__ASSERT(pshared == 0, "pshared should be 0");
64 
65 	k_sem_init(semaphore, value, CONFIG_SEM_VALUE_MAX);
66 
67 	return 0;
68 }
69 
70 /**
71  * @brief Unlock a semaphore.
72  *
73  * See IEEE 1003.1
74  */
sem_post(sem_t * semaphore)75 int sem_post(sem_t *semaphore)
76 {
77 	if (semaphore == NULL) {
78 		errno = EINVAL;
79 		return -1;
80 	}
81 
82 	k_sem_give(semaphore);
83 	return 0;
84 }
85 
86 /**
87  * @brief Try time limited locking a semaphore.
88  *
89  * See IEEE 1003.1
90  */
sem_timedwait(sem_t * semaphore,struct timespec * abstime)91 int sem_timedwait(sem_t *semaphore, struct timespec *abstime)
92 {
93 	int32_t timeout;
94 	struct timespec current;
95 	int64_t current_ms, abstime_ms;
96 
97 	__ASSERT(abstime, "abstime pointer NULL");
98 
99 	if ((abstime->tv_sec < 0) || (abstime->tv_nsec >= NSEC_PER_SEC)) {
100 		errno = EINVAL;
101 		return -1;
102 	}
103 
104 	if (clock_gettime(CLOCK_REALTIME, &current) < 0) {
105 		return -1;
106 	}
107 
108 	abstime_ms = (int64_t)_ts_to_ms(abstime);
109 	current_ms = (int64_t)_ts_to_ms(&current);
110 
111 	if (abstime_ms <= current_ms) {
112 		timeout = 0;
113 	} else {
114 		timeout = (int32_t)(abstime_ms - current_ms);
115 	}
116 
117 	if (k_sem_take(semaphore, K_MSEC(timeout))) {
118 		errno = ETIMEDOUT;
119 		return -1;
120 	}
121 
122 	return 0;
123 }
124 
125 /**
126  * @brief Lock a semaphore if not taken.
127  *
128  * See IEEE 1003.1
129  */
sem_trywait(sem_t * semaphore)130 int sem_trywait(sem_t *semaphore)
131 {
132 	if (k_sem_take(semaphore, K_NO_WAIT) == -EBUSY) {
133 		errno = EAGAIN;
134 		return -1;
135 	} else {
136 		return 0;
137 	}
138 }
139 
140 /**
141  * @brief Lock a semaphore.
142  *
143  * See IEEE 1003.1
144  */
sem_wait(sem_t * semaphore)145 int sem_wait(sem_t *semaphore)
146 {
147 	/* With K_FOREVER, may return only success. */
148 	(void)k_sem_take(semaphore, K_FOREVER);
149 	return 0;
150 }
151