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