1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** POSIX wrapper for THREADX */
17 /** */
18 /** */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 /* Include necessary system files. */
24
25 #include "tx_api.h" /* Threadx API */
26 #include "pthread.h" /* Posix API */
27 #include "px_int.h" /* Posix helper functions */
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* sem_open PORTABLE C */
35 /* 6.2.0 */
36 /* AUTHOR */
37 /* */
38 /* William E. Lamie, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function creates/initialize a semaphore. */
43 /* */
44 /* INPUT */
45 /* */
46 /* name Semaphore name */
47 /* oflags Flags */
48 /* mode Optional parameter */
49 /* value Optional parameter */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* sem Semaphore descriptor */
54 /* */
55 /* CALLS */
56 /* */
57 /* posix_in_thread_context Make sure caller is thread */
58 /* posix_find_sem Finds the required semaphore */
59 /* posix_get_new_sem Get new semaphore block */
60 /* posix_internal_error Internal posix error */
61 /* tx_semaphore_create ThreadX semaphore create */
62 /* posix_set_sem_name Sets name for semaphore */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* Application Code */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
73 /* 10-31-2022 Scott Larson Update comparison with NULL, */
74 /* resulting in version 6.2.0 */
75 /* */
76 /**************************************************************************/
sem_open(const CHAR * name,ULONG oflag,...)77 sem_t * sem_open(const CHAR * name, ULONG oflag, ...)
78 {
79
80 TX_INTERRUPT_SAVE_AREA
81
82 TX_SEMAPHORE *TheSem;
83 sem_t *semid;
84 ULONG retval;
85 ULONG len;
86 sem_t *posix_sem;
87 va_list vl;
88 UINT value;
89 mode_t mode;
90
91 /* Make sure we're calling this routine from a thread context. */
92 if (!posix_in_thread_context())
93 {
94 /* return POSIX error. */
95 posix_internal_error(444);
96
97 /* return error. */
98 return (( sem_t * )SEM_FAILED);
99 }
100
101 /* Find length of the name. The actual length is not known yet. */
102 len = strlen(name);
103
104 if(len > SEM_NAME_MAX)
105 {
106 /* Set appropriate errno. */
107 posix_errno = ENAMETOOLONG;
108 posix_set_pthread_errno(ENAMETOOLONG);
109
110 /* Return ERROR. */
111 return (( sem_t * ) SEM_FAILED);
112 }
113
114 /* Check if semaphore exists. */
115 if((semid = posix_find_sem(name)) != NULL)
116 {
117 if(semid->unlink_flag ==TX_TRUE )
118 {
119 /* Return error. */
120 posix_errno = EINVAL;
121 posix_set_pthread_errno(EINVAL);
122 return(( sem_t * )SEM_FAILED);
123 }
124 }
125
126 /* Semaphore not found. */
127 if(!(semid))
128 {
129 /* Check if flag set is O_EXCL. */
130 if( oflag == O_EXCL )
131 {
132
133 /* Set error for sem does not exist and O_CREAT not set. */
134 posix_errno = ENOENT;
135 posix_set_pthread_errno(ENOENT);
136
137 /* Return the SEM_FAILED error. */
138 return(( sem_t * )SEM_FAILED);
139 }
140 if( (oflag == O_CREAT) || ( (oflag & (O_CREAT|O_EXCL )) == (O_CREAT|O_EXCL) ) )
141 {
142
143 /* Get the variable arguments pointers. */
144
145 va_start( vl, oflag );
146
147 mode = va_arg( vl, mode_t);
148 mode = mode; /* just to keep compiler happy */
149
150 value = va_arg( vl, ULONG);
151
152 if(value > SEM_VALUE_MAX)
153 {
154 /* Semaphore value large. */
155 posix_errno = EINVAL;
156 posix_set_pthread_errno(EINVAL);
157
158 /* Return ERROR */
159 return (( sem_t * )SEM_FAILED);
160
161 }
162
163 /* Disable interrupts. */
164 TX_DISABLE
165
166 /* Get a new semaphore from the POSIX semaphore pool. */
167 TheSem = posix_get_new_sem();
168
169 /* Make sure we actually got a semaphore. */
170 if (!TheSem)
171 {
172 /* Semaphore cannot be initialized due to resource constraint. */
173 posix_errno = ENOSPC;
174 posix_set_pthread_errno(ENOSPC);
175
176 /* Restore interrupts. */
177 TX_RESTORE
178
179 /* return appropriate error code. */
180 return(( sem_t * )SEM_FAILED);
181 }
182
183 /* Set the semaphore name. */
184 posix_set_sem_name((sem_t *)TheSem, ( CHAR * ) name);
185
186 /* Now actually create the ThreadX semaphore. */
187 posix_sem = (struct POSIX_SEMAPHORE_STRUCT *)TheSem;
188 retval = tx_semaphore_create(TheSem, ( CHAR * ) posix_sem->sem_name , value);
189
190 /* Make sure it worked. */
191 if (retval)
192 {
193 /* Return generic error. */
194 posix_internal_error(100);
195
196 /* Restore interrupts. */
197 TX_RESTORE
198
199 /* Return appropriate error code. */
200 return(( sem_t * )SEM_FAILED);
201 }
202
203 /* Add the calling thread to the thread list. */
204 posix_sem -> count += 1;
205
206 /* Set initial count */
207 posix_sem->refCnt = value;
208
209 /* Give the caller the semaphore ID. */
210 semid = (sem_t * )TheSem;
211
212 /* Restore interrupts. */
213 TX_RESTORE
214
215 /* All done. */
216 return(semid);
217 }
218
219 }
220 /* Semaphore found. */
221 if(semid)
222 {
223
224 /* Check if flags are O_CREAT|O_EXCL. */
225 if( (oflag == O_EXCL) || (oflag & (O_CREAT|O_EXCL )) == (O_CREAT|O_EXCL) )
226 {
227 /* Set appropriate errno. */
228 posix_errno = EEXIST;
229 posix_set_pthread_errno(EEXIST);
230
231 /* Return ERROR. */
232 return (( sem_t * ) SEM_FAILED);
233 }
234
235 /* Check if flag is only O_CREAT. */
236 if( (oflag == O_CREAT) || (oflag==0))
237 {
238 /* Disable interrupts. */
239 TX_DISABLE
240
241 /* Add the calling thread to the thread list. */
242 semid -> count++;
243
244 /* Restore interrupts. */
245 TX_RESTORE
246
247 /* Return semaphore. */
248 return (( sem_t * ) semid);
249 }
250 }
251
252 /* Semaphore value large. */
253 posix_errno = EINVAL;
254 posix_set_pthread_errno(EINVAL);
255
256 /* Return ERROR. */
257 return (( sem_t * ) SEM_FAILED);
258 }
259