?? rt_ipc.c
字號(hào):
/* * rt_ipc.c -- intertask communication primitives for Real-Time Linux * * Copyright (C) 1997 Jerry Epplin. All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History: * 17-Jul-97 jhe V0.1 Original. * 28-Jul-97 jhe V0.2 Timeouts on semaphores. Message queues. * 15-Aug-97 jhe V0.3 rt_ipc fifos. Modified semantics of timeouts. */#define IPC_VERSION "0.3"#include <linux/module.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/errno.h>#include <asm/system.h>#include <linux/malloc.h>#include <rtl_sched.h>#include <rtl_sync.h>#include <rtl_fifo.h>#include <asm/rt_irq.h>#include "rt_ipc.h"extern int rtl_schedule(void);#include <rtl_sync.h>#ifdef CONFIG_SMP#error rt_ipc does not work on SMP yetextern spinlock_t fifo_spinlock;#define RTL_SPIN_LOCK fifo_spinlock#endif#define IPC_DATA_INDEX 0/************************************************************************* * rt_sem_init -- initialize a real-time semaphore * * Called to initialize a real-time semaphore. 'sem' must point to a * statically allocated structure. 'type' is RT_SEM_BINARY or * RT_SEM_COUNTING. 'init_val' is the initial value of the semaphore * (usually 0). * * Returns 0 if successful, -EINVAL if called incorrectly. *************************************************************************/int rt_sem_init(rt_sem_t *sem, RT_SEMTYPE type, int init_val){ int ret = 0; if (init_val < 0 || (type == RT_SEM_BINARY && init_val > 1)) ret = -EINVAL; /* binary sem must have 0 or 1 */ else { sem->magic = RT_SEM_MAGIC; sem->val = init_val; sem->type = type; sem->wait_list = NULL; } return ret;}/************************************************************************* * rt_sem_destroy -- remove a real-time semaphore * * Removes a semaphore previously created with rt_sem_init(). Semaphore * deletion safety is implemented; i.e., any tasks blocked on this * semaphore when it is destroyed are allowed to run. * * Returns 0 if successful, -EINVAL if 'sem' is not a valid rt_sem_t. *************************************************************************/int rt_sem_destroy(rt_sem_t *sem){ int ret = 0; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; else /* unblock any tasks blocked on this sem */ while (sem->val < 0) rt_sem_post(sem); return ret;}/************************************************************************* * unlink_sem_task -- remove a task from a wait list * * Removes a task from the list of tasks waiting on a semaphore. *************************************************************************/static void unlink_sem_task(RT_TASK_ENTRY *to_unlink, rt_sem_t *sem){ if (to_unlink->next != NULL) to_unlink->next->prev = to_unlink->prev; if (to_unlink->prev == NULL) sem->wait_list = to_unlink->next; else to_unlink->prev->next = to_unlink->next;}/************************************************************************* * unlink_mq_task -- remove a task from a wait list * * Removes a task from the list of tasks waiting on a message queue. *************************************************************************/static void unlink_mq_task(RT_TASK_ENTRY *to_unlink, rt_mq_t *mq){ if (to_unlink->next != NULL) to_unlink->next->prev = to_unlink->prev; if (to_unlink->prev == NULL) mq->wait_list = to_unlink->next; else to_unlink->prev->next = to_unlink->next;}/* cope with the changed priority system */#define GET_PRIO(task) (sched_get_priority_max(0) - (*(task))->sched_param.sched_priority)#define rtl_current (pthread_self()->user[IPC_DATA_INDEX])/* #define rtl_current ((LOCAL_SCHED)-> rtl_current); *//************************************************************************* * rt_sem_post -- semaphore post operation * * The semaphore post (sometimes known as 'give', 'signal', or 'V') operation. * If tasks are waiting for the semaphore, the one with the highest priority * is allowed to run. * * Returns 0 if successful, or -EINVAL if the semaphore is not valid. *************************************************************************/int rt_sem_post(rt_sem_t *sem){ int ret = 0; int flags; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; /* invalid rt_sem_t structure */ else { RT_TASK_ENTRY *to_run = NULL; rtl_critical(flags); if (sem->val < 0) /* one or more tasks are waiting for this sem */ { /* find the waiting task with the highest priority */ RT_TASK_ENTRY *t; /* search exhaustively all waiting tasks. I don't want to keep */ /* the list in priority order because I don't want to assume */ /* the task priorities won't change. */ for (t=sem->wait_list ; t!=NULL ; t=t->next) if (to_run == NULL || GET_PRIO(t->task) < GET_PRIO(to_run->task)) to_run = t; /* remove the task to be run from the wait_list */ unlink_sem_task(to_run, sem); /* mark that task as no longer waiting at sem */ ((RT_TASK_IPC *)(to_run->task))->sem_at = NULL; } /* binary semaphores never exceed 1 */ if (sem->val < 1 || sem->type == RT_SEM_COUNTING) ++sem->val; if (to_run != NULL) { /* rt_sem_wait() returned because of a post, not */ /* because of a timeout */ ((RT_TASK_IPC *)(to_run->task))->timed_out = 0; rt_task_wakeup(to_run->task); } rtl_end_critical(flags); } return ret;}/************************************************************************* * rt_sem_wait -- semaphore wait operation (blocking) * * The semaphore wait (sometimes known as 'take' or 'P') operation. * If the semaphore is not available, the calling task blocks until * it is. 'timeout' is an optional timeout period. If 'timeout' is * RT_WAIT_FOREVER, the function does not time out. If 'timeout' is * RT_NO_WAIT and the semaphore is not available, rt_sem_wait() returns * immediately. If 'timeout' is any other value, it represent a time * at which the call to rt_sem_wait() should time out. If that time * is reached, rt_sem_wait() returns with -ETIME. * * Returns 0 if successful, -ETIME if the operation timed out, -EAGAIN if * RT_NO_WAIT was specified and the semaphore was not available, or -EINVAL * if the semaphore is not valid. *************************************************************************/int rt_sem_wait(rt_sem_t *sem, RTIME timeout){ int ret = 0; int flags; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; /* invalid rt_sem_t structure */ else { rtl_critical(flags); if (sem->val <= 0) /* sem not available -- task must wait */ { if (timeout == RT_NO_WAIT) ret = -EAGAIN; else { RT_TASK_ENTRY *to_add = &(((RT_TASK_IPC *)rtl_current)->rte); /* put task on wait_list */ to_add->task = rtl_current; to_add->prev = NULL; to_add->next = sem->wait_list; if (to_add->next != NULL) to_add->next->prev = to_add; sem->wait_list = to_add; /* indicate which sem the task is blocked at */ ((RT_TASK_IPC *)rtl_current)->sem_at = sem; /* and decrement sem value */ --sem->val; /* and finally, block */ if (timeout == RT_WAIT_FOREVER) rt_task_suspend(rtl_current); /* suspend until post */ else { /* assume call timed out. If this is not the case, */ /* rt_sem_post() will clear this flag */ ((RT_TASK_IPC *)rtl_current)->timed_out = 1; /* delay until either post occurs or timeout occurs */ rt_task_delay(timeout); if (((RT_TASK_IPC *)rtl_current)->timed_out) { /* timeout occurred -- undo everything and return */ unlink_sem_task(to_add, sem); ++sem->val; ret = -ETIME; } } } } else --sem->val; rtl_end_critical(flags); } return ret;}/************************************************************************* * rt_sem_trywait -- semaphore wait operation (unblocking) * * The semaphore wait (sometimes known as 'take' or 'P') operation. * The function returns immediately whether or not the semaphore is * available. * * Returns 0 if successful, -EAGAIN if the semaphore is not available, * or -EINVAL if the semaphore is not valid. *************************************************************************/int rt_sem_trywait(rt_sem_t *sem){ int ret = 0; int flags; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; /* invalid rt_sem_t structure */ else { rtl_critical(flags); if (sem->val <= 0) /* sem not available -- task must wait */ ret = -EAGAIN; else --sem->val; rtl_end_critical(flags); } return ret;}/************************************************************************* * rt_task_ipc_init -- rt_ipc version of rt_task_init() * * RT-Linux programs using rt_ipc should use rt_task_ipc_init instead of * rt_task_init(). It initializes some rt_ipc variables, then calls * rt_task_init(). Note that all parameters are the same as in rt_task_init() * except 'task', which is an RT_TASK_IPC instead of an RT_TASK. * * Returns 0 if successful, -EINVAL if the 'task' structure is already in * use by another task, or -ENOMEM if a memory allocation error occurred. *************************************************************************/
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -