incubator-nuttx/include/semaphore.h

252 lines
8.1 KiB
C

/****************************************************************************
* include/semaphore.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <limits.h>
#include <time.h>
#include <nuttx/queue.h>
/****************************************************************************
* 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; /* Slot for old and new holder */
# endif
#endif
#ifdef CONFIG_PRIORITY_PROTECT
uint8_t ceiling; /* The priority ceiling owned by mutex */
uint8_t saved; /* The saved priority of thread before boost */
#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}
# 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 */