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