/**************************************************************************** * include/semaphore.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ #ifndef __INCLUDE_SEMAPHORE_H #define __INCLUDE_SEMAPHORE_H /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Values for protocol attribute */ #define SEM_PRIO_NONE 0 #define SEM_PRIO_INHERIT 1 #define SEM_PRIO_PROTECT 2 #define SEM_PRIO_MASK 3 #define SEM_TYPE_MUTEX 4 /* Value returned by sem_open() in the event of a failure. */ #define SEM_FAILED NULL /**************************************************************************** * Public Type Declarations ****************************************************************************/ /* This structure contains information about the holder of a semaphore */ #ifdef CONFIG_PRIORITY_INHERITANCE struct tcb_s; /* Forward reference */ struct sem_s; struct semholder_s { #if CONFIG_SEM_PREALLOCHOLDERS > 0 FAR struct semholder_s *flink; /* List of semaphore's holder */ #endif FAR struct semholder_s *tlink; /* List of task held semaphores */ FAR struct sem_s *sem; /* Ths corresponding semaphore */ FAR struct tcb_s *htcb; /* Ths corresponding TCB */ int16_t counts; /* Number of counts owned by this holder */ }; #if CONFIG_SEM_PREALLOCHOLDERS > 0 # define SEMHOLDER_INITIALIZER {NULL, NULL, NULL, NULL, 0} # define INITIALIZE_SEMHOLDER(h) \ do { \ (h)->flink = NULL; \ (h)->tlink = NULL; \ (h)->sem = NULL; \ (h)->htcb = NULL; \ (h)->counts = 0; \ } while (0) #else # define SEMHOLDER_INITIALIZER {NULL, NULL, NULL, 0} # define INITIALIZE_SEMHOLDER(h) \ do { \ (h)->tlink = NULL; \ (h)->sem = NULL; \ (h)->htcb = NULL; \ (h)->counts = 0; \ } while (0) #endif #endif /* CONFIG_PRIORITY_INHERITANCE */ #define SEM_WAITLIST_INITIALIZER {NULL, NULL} /* This is the generic semaphore structure. */ struct sem_s { volatile int16_t semcount; /* >0 -> Num counts available */ /* <0 -> Num tasks waiting for semaphore */ /* If priority inheritance is enabled, then we have to keep track of which * tasks hold references to the semaphore. */ uint8_t flags; /* See SEM_PRIO_* definitions */ dq_queue_t waitlist; #ifdef CONFIG_PRIORITY_INHERITANCE # if CONFIG_SEM_PREALLOCHOLDERS > 0 FAR struct semholder_s *hhead; /* List of holders of semaphore counts */ # else struct semholder_s holder[2]; /* Slot for old and new holder */ # endif #endif }; typedef struct sem_s sem_t; /* Initializers */ #ifdef CONFIG_PRIORITY_INHERITANCE # if CONFIG_SEM_PREALLOCHOLDERS > 0 /* semcount, flags, waitlist, hhead */ # define SEM_INITIALIZER(c) \ {(c), 0, SEM_WAITLIST_INITIALIZER, NULL} # else /* semcount, flags, waitlist, holder[2] */ # define SEM_INITIALIZER(c) \ {(c), 0, SEM_WAITLIST_INITIALIZER, {SEMHOLDER_INITIALIZER, SEMHOLDER_INITIALIZER}} # endif #else /* semcount, flags, waitlist */ # define SEM_INITIALIZER(c) \ {(c), 0, SEM_WAITLIST_INITIALIZER} #endif # define SEM_WAITLIST(sem) (&((sem)->waitlist)) /**************************************************************************** * Public Data ****************************************************************************/ #ifdef __cplusplus #define EXTERN extern "C" extern "C" { #else #define EXTERN extern #endif /**************************************************************************** * Public Function Prototypes ****************************************************************************/ /* Counting Semaphore Interfaces (based on POSIX APIs) */ int sem_init(FAR sem_t *sem, int pshared, unsigned int value); int sem_destroy(FAR sem_t *sem); int sem_wait(FAR sem_t *sem); int sem_timedwait(FAR sem_t *sem, FAR const struct timespec *abstime); int sem_clockwait(FAR sem_t *sem, clockid_t clockid, FAR const struct timespec *abstime); int sem_trywait(FAR sem_t *sem); int sem_post(FAR sem_t *sem); int sem_getvalue(FAR sem_t *sem, FAR int *sval); #ifdef CONFIG_FS_NAMED_SEMAPHORES FAR sem_t *sem_open(FAR const char *name, int oflag, ...); int sem_close(FAR sem_t *sem); int sem_unlink(FAR const char *name); #endif /**************************************************************************** * Name: sem_setprotocol * * Description: * Set semaphore protocol attribute. * * One particularly important use of this function is when a semaphore * is used for inter-task communication like: * * TASK A TASK B * sem_init(sem, 0, 0); * sem_wait(sem); * sem_post(sem); * Awakens as holder * * In this case priority inheritance can interfere with the operation of * the semaphore. The problem is that when TASK A is restarted it is a * holder of the semaphore. However, it never calls sem_post(sem) so it * becomes *permanently* a holder of the semaphore and may have its * priority boosted when any other task tries to acquire the semaphore. * * The fix is to call sem_setprotocol(SEM_PRIO_NONE) immediately after * the sem_init() call so that there will be no priority inheritance * operations on this semaphore. * * Input Parameters: * sem - A pointer to the semaphore whose attributes are to be * modified * protocol - The new protocol to use * * Returned Value: * This function is exposed as a non-standard application interface. It * returns zero (OK) if successful. Otherwise, -1 (ERROR) is returned and * the errno value is set appropriately. * ****************************************************************************/ int sem_setprotocol(FAR sem_t *sem, int protocol); /**************************************************************************** * Name: sem_getprotocol * * Description: * Return the value of the semaphore protocol attribute. * * Input Parameters: * sem - A pointer to the semaphore whose attributes are to be * queried. * protocol - The user provided location in which to store the protocol * value. * * Returned Value: * This function is exposed as a non-standard application interface. It * returns zero (OK) if successful. Otherwise, -1 (ERROR) is returned and * the errno value is set appropriately. * ****************************************************************************/ int sem_getprotocol(FAR sem_t *sem, FAR int *protocol); #undef EXTERN #ifdef __cplusplus } #endif #endif /* __INCLUDE_SEMAPHORE_H */