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