?? fifos.c
字號:
/** * @ingroup fifos * @ingroup fifos_ipc * @ingroup fifos_sem * @file * * Implementation of the @ref fifos "RTAI FIFO module". * * @author Paolo Mantegazza * * @note Copyright © 1999-2003 Paolo Mantegazza <mantegazza@aero.polimi.it> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* ACKNOWLEDGEMENTS: - nice proc file contributed by Steve Papacharalambous (stevep@zentropix.com);- added proc handler info contributed by Rich Walker (rw@shadow.org.uk)- 11-19-2001, Truxton Fulton (trux@truxton.com) fixed a race in mbx_get.- 10-23-2003 added atomic send contributed by Jan Kiszka (kiszka@rts.uni-hannover.de) and expanded it to rtf_get_if.- 12-10-2003 a fix of rtf_resize odds contributed by Abramo Bagnara (abramo.bagnara@tin.it).*//** * @defgroup fifos RTAI FIFO module * * See @ref fifos_overview "the general overview of RTAI fifos". *//** * @ingroup fifos * @defgroup fifos_ipc Inter-process communications. * * RTAI FIFO communication functions. * * RTAI fifos maintain full compatibility with those available in NMT_RTLinux * while adding many other useful services that avoid the clumsiness of * Unix/Linux calls. So if you need portability you should bent yourself to the * use of select for timing out IO operations, while if you have not to satisfy * such constraints use the available simpler, and more direct, RTAI fifos * specific services. * * In the table below the standard Unix/Linux services in user space are * enclosed in []. See standard Linux man pages if you want to use them, they * need not be explained here. * * <CENTER><TABLE> * <TR><TD> Called from RT task </TD><TD> Called from Linux process </TD></TR> * <TR><TD> #rtf_create </TD><TD> #rtf_open_sized <BR> * [open] </TD></TR> * <TR><TD> #rtf_destroy </TD><TD> [close] </TD></TR> * <TR><TD> #rtf_reset </TD><TD> #rtf_reset </TD></TR> * <TR><TD> #rtf_resize </TD><TD> #rtf_resize </TD></TR> * <TR><TD> #rtf_get </TD><TD> [read] <BR> * #rtf_read_timed <BR> * #rtf_read_all_at_once </TD></TR> * <TR><TD> #rtf_put </TD><TD> [write] <BR> * #rtf_write_timed </TD></TR> * <TR><TD> #rtf_create_handler </TD><TD> </TD></TR> * <TR><TD> </TD><TD> #rtf_suspend_timed </TD></TR> * <TR><TD> </TD><TD> #rtf_set_async_sig </TD></TR> * </TABLE></CENTER> * * In Linux, fifos have to be created by : * @verbatim $ mknod /dev/rtf<x> c 150 <x> @endverbatim * where \<x\> is the minor device number, from 0 to 63; thus on the Linux side * RTL fifos can be used as standard character devices. As it was said above to * use standard IO operations on such devices there is no need to explain * anything, go directly to Linux man pages. RTAI fifos specific services * available in kernel and user space are instead explained here. * * What is important to remember is that in the user space side you address * fifos through the file descriptor you get at fifo device opening while in * kernel space you directly address them by their minor number. So you will * mate the @a fd you get in user space by using * @verbatim open(/dev/rtfxx,...) @endverbatim * to the integer @p xx you will use in kernel space. * * @note RTAI fifos should be used just with applications that use only real * time interrupt handlers, so that no RTAI scheduler is installed, or if you * need compatibility with NMT RTL. If you are working with any RTAI scheduler * already installed you are strongly invited to think about avoiding them, use * LXRT instead. * * It is far better and flexible, and if you really like it the fifos way * mailboxes are a one to one, more effective, substitute. After all RTAI * fifos are implemented on top of them. *//** * @ingroup fifos * @defgroup fifos_sem Semaphores. * * RTAI FIFO semaphore functions. * * Fifos have an embedded synchronization capability, however using them only * for such a purpose can be clumsy. So RTAI fifos have binary semaphores for * that purpose. Note that, as for put and get fifos functions, only nonblocking * functions are available in kernel space. * * <CENTER><TABLE> * <TR><TD> Called from RT task </TD><TD> Called from Linux process </TD></TR> * <TR><TD> #rtf_sem_init </TD><TD> #rtf_sem_init </TD></TR> * <TR><TD> #rtf_sem_post </TD><TD> #rtf_sem_post </TD></TR> * <TR><TD> #rtf_sem_trywait </TD><TD> #rtf_sem_wait <BR> * #rtf_sem_trywait <BR> * #rtf_sem_timed_wait </TD></TR> * <TR><TD> #rtf_sem_destroy </TD><TD> #rtf_sem_destroy </TD></TR> * </TABLE></CENTER> * * To add a bit of confusion (J), with respect to RTAI schedulers semaphore * functions, fifos semaphore functions names follow the POSIX mnemonics. * * It should be noted that semaphores are associated to a fifo for * identification purposes. So it is once more important to remember is that * in the user space side you address fifos through the file descriptor you get * at fifo device opening while in kernel space you directly address them by * their minor number. So you will mate the fd you get in user space by * @verbatim open(/dev/rtfxx,) @endverbatim to the integer @p xx youll use in * kernel space. */#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/vmalloc.h>#include <linux/poll.h>#include <linux/termios.h>#include <linux/tty_driver.h>#include <linux/console.h>#include <linux/config.h>#include <linux/slab.h>#include <linux/devfs_fs_kernel.h>#include <linux/stat.h>#include <linux/proc_fs.h>#include <rtai_fifos.h>#include <rtai_trace.h>#include <rtai_proc_fs.h>#include <rtai_sched.h>#include <rtai_lxrt.h>MODULE_LICENSE("GPL");/* these are copied from <rt/rt_compat.h> */#define rtf_save_flags_and_cli(x) do{x=rt_spin_lock_irqsave(&rtf_lock);}while(0)#define rtf_restore_flags(x) rt_spin_unlock_irqrestore((x),&rtf_lock)#define rtf_spin_lock_irqsave(x,y) do{x=rt_spin_lock_irqsave(&(y));}while(0)#define rtf_spin_unlock_irqrestore(x,y) rt_spin_unlock_irqrestore((x),&(y))#define rtf_request_srq(x) rt_request_srq(0, (x), 0)#define rtf_free_srq(x) rt_free_srq((x))#define rtf_pend_srq(x) rt_pend_linux_srq((x))#ifdef CONFIG_PROC_FSstatic int rtai_proc_fifo_register(void);static void rtai_proc_fifo_unregister(void);#endiftypedef struct lx_queue { struct lx_queue *prev; struct lx_queue *next; struct lx_task_struct *task;} F_QUEUE;typedef struct lx_semaphore { int free; int qtype; F_QUEUE queue;} F_SEM;typedef struct lx_task_struct { int blocked; int priority; F_QUEUE queue; struct task_struct *task;} LX_TASK;typedef struct lx_mailbox { int size; // size of the entire buffer int fbyte; // head int lbyte; // tail int avbs; // bytes available in the buffer int frbs; // free bytes in the buffer char *bufadr; F_SEM sndsem, rcvsem; struct task_struct *waiting_task; spinlock_t buflock;} F_MBX;typedef struct rt_fifo_struct { F_MBX mbx; // MUST BE THE FIRST! int opncnt; int malloc_type; int pol_asyn_pended; wait_queue_head_t pollq; struct fasync_struct *asynq; int (*handler)(unsigned int arg); F_SEM sem; char name[RTF_NAMELEN+1];} FIFO;static int fifo_srq, async_sig;static spinlock_t rtf_lock = SPIN_LOCK_UNLOCKED;static spinlock_t rtf_name_lock = SPIN_LOCK_UNLOCKED;#define MAX_FIFOS 64//static FIFO fifo[MAX_FIFOS] = {{{0}}};static FIFO *fifo;#define MAXREQS 64 // KEEP IT A POWER OF 2!!!static struct { int in, out; struct task_struct *task[MAXREQS]; } taskq;static struct { int in, out; FIFO *fifo[MAXREQS]; } pol_asyn_q;static RT_TASK *rt_base_linux_task;static int do_nothing(unsigned int arg) { return 0; }static inline void enqueue_blocked(LX_TASK *task, F_QUEUE *queue, int qtype, int priority){ F_QUEUE *q; task->blocked = 1; q = queue; if (!qtype) { while ((q = q->next) != queue && (q->task)->priority >= priority); } q->prev = (task->queue.prev = q->prev)->next = &(task->queue); task->queue.next = q;}static inline void dequeue_blocked(LX_TASK *task){ task->blocked = 0; (task->queue.prev)->next = task->queue.next; (task->queue.next)->prev = task->queue.prev;}static inline void mbx_sem_signal(F_SEM *sem, FIFO *fifop){ unsigned long flags; LX_TASK *task; rtf_save_flags_and_cli(flags); if ((task = (sem->queue.next)->task)) { dequeue_blocked(task); taskq.task[taskq.in] = task->task; taskq.in = (taskq.in + 1) & (MAXREQS - 1); rtf_pend_srq(fifo_srq); } else { sem->free = 1; if (fifop && !(fifop->pol_asyn_pended) && (((F_MBX *)fifop)->avbs || ((F_MBX *)fifop)->frbs) && (waitqueue_active(&fifop->pollq) || fifop->asynq)) { fifop->pol_asyn_pended = 1; pol_asyn_q.fifo[pol_asyn_q.in] = fifop; pol_asyn_q.in = (pol_asyn_q.in + 1) & (MAXREQS - 1); rtf_pend_srq(fifo_srq); } } rtf_restore_flags(flags); return;}static inline void mbx_signal(F_MBX *mbx){ unsigned long flags; struct task_struct *task; rtf_save_flags_and_cli(flags); if ((task = mbx->waiting_task)) { mbx->waiting_task = 0; taskq.task[taskq.in] = task; taskq.in = (taskq.in + 1) & (MAXREQS - 1); rtf_pend_srq(fifo_srq); } rtf_restore_flags(flags); return;}static inline int mbx_sem_wait_if(F_SEM *sem){ unsigned long flags; rtf_save_flags_and_cli(flags); if (sem->free) { sem->free = 0; rtf_restore_flags(flags); return 1; } rtf_restore_flags(flags); return 0;}static inline int mbx_sem_wait(F_SEM *sem){ unsigned long flags; LX_TASK task; int ret; ret = 0; rtf_save_flags_and_cli(flags); if (!sem->free) { task.queue.task = &task; task.priority = current->rt_priority; enqueue_blocked(&task, &sem->queue, sem->qtype, task.priority); task.task = current; rtf_restore_flags(flags); current->state = TASK_INTERRUPTIBLE; schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; } rtf_save_flags_and_cli(flags); if (task.blocked) { dequeue_blocked(&task); if (!(sem->queue.next)->task) { sem->free = 1; } rtf_restore_flags(flags); if (!ret) { ret = -1; } } } else { sem->free = 0; } rtf_restore_flags(flags); return ret;}static inline int mbx_wait(F_MBX *mbx, int *fravbs){ unsigned long flags; rtf_save_flags_and_cli(flags); if (!(*fravbs)) { mbx->waiting_task = current; current->state = TASK_INTERRUPTIBLE; rtf_restore_flags(flags); schedule(); if (signal_pending(current)) { return -ERESTARTSYS; } rtf_save_flags_and_cli(flags); if (mbx->waiting_task == current) { mbx->waiting_task = 0; rtf_restore_flags(flags); return -1; } } rtf_restore_flags(flags); return 0;}static inline int mbx_sem_wait_timed(F_SEM *sem, int delay){ unsigned long flags; LX_TASK task; rtf_save_flags_and_cli(flags); if (!sem->free) { task.queue.task = &task; task.priority = current->rt_priority; enqueue_blocked(&task, &sem->queue, sem->qtype, task.priority); task.task = current; rtf_restore_flags(flags); current->state = TASK_INTERRUPTIBLE; schedule_timeout(delay); if (signal_pending(current)) { return -ERESTARTSYS; } rtf_save_flags_and_cli(flags); if (task.blocked) { dequeue_blocked(&task); if (!((sem->queue.next)->task)) { sem->free = 1; } rtf_restore_flags(flags); return -1; } } else { sem->free = 0; } rtf_restore_flags(flags); return 0;}static inline int mbx_wait_timed(F_MBX *mbx, int *fravbs, int delay){ unsigned long flags; rtf_save_flags_and_cli(flags); if (!(*fravbs)) { mbx->waiting_task = current; rtf_restore_flags(flags); current->state = TASK_INTERRUPTIBLE; schedule_timeout(delay); if (signal_pending(current)) { return -ERESTARTSYS; } rtf_save_flags_and_cli(flags); if (mbx->waiting_task == current) {; mbx->waiting_task = 0; rtf_restore_flags(flags); return -1; } } rtf_restore_flags(flags); return 0;}#define MOD_SIZE(indx) ((indx) < mbx->size ? (indx) : (indx) - mbx->size)static inline int mbx_put(F_MBX *mbx, char **msg, int msg_size, int lnx){ unsigned long flags; int tocpy; while (msg_size > 0 && mbx->frbs) { if ((tocpy = mbx->size - mbx->lbyte) > msg_size) { tocpy = msg_size; } if (tocpy > mbx->frbs) { tocpy = mbx->frbs; } if (lnx) { copy_from_user(mbx->bufadr + mbx->lbyte, *msg, tocpy); } else { memcpy(mbx->bufadr + mbx->lbyte, *msg, tocpy); } rtf_spin_lock_irqsave(flags, mbx->buflock); mbx->lbyte = MOD_SIZE(mbx->lbyte + tocpy); mbx->frbs -= tocpy; mbx->avbs += tocpy; rtf_spin_unlock_irqrestore(flags, mbx->buflock); msg_size -= tocpy; *msg += tocpy; } return msg_size;}static inline int mbx_ovrwr_put(F_MBX *mbx, char **msg, int msg_size, int lnx){ unsigned long flags; int tocpy,n; if ((n = msg_size - mbx->size) > 0) { *msg += n; msg_size -= n; } while (msg_size > 0) { if (mbx->frbs) { if ((tocpy = mbx->size - mbx->lbyte) > msg_size) { tocpy = msg_size; } if (tocpy > mbx->frbs) { tocpy = mbx->frbs; } if (lnx) { copy_from_user(mbx->bufadr + mbx->lbyte, *msg, tocpy); } else { memcpy(mbx->bufadr + mbx->lbyte, *msg, tocpy); } rtf_spin_lock_irqsave(flags, mbx->buflock); mbx->frbs -= tocpy; mbx->avbs += tocpy; rtf_spin_unlock_irqrestore(flags, mbx->buflock); msg_size -= tocpy; *msg += tocpy; mbx->lbyte = MOD_SIZE(mbx->lbyte + tocpy); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -