?? rt_ipc.c
字號:
* Dequeues the data 'msg' from the message queue 'mq'. The data will * be of the size with which rt_mq_init() was called. 'wait' specifies an * optional timeout period. If 'wait' is RT_NO_WAIT, rt_mq_receive() * returns immediately even if no messages are present. If * 'wait' is RT_WAIT_FOREVER, no timeout occurs. If 'wait' is any other * value, it reflects the time at which rt_mq_receive() will wake up * and return with -ETIME. * * Returns 0 if successful, -ETIME if the operation timed out, -EAGAIN if * RT_NO_WAIT was specified and the operation could not be completed * immediately, or -EINVAL if the rt_mq_t is not valid. *************************************************************************/int rt_mq_receive(rt_mq_t *mq, char *msg, RTIME wait){ int ret = 0; if (mq->magic != RT_MQ_MAGIC) ret = -EINVAL; /* invalid rt_mq_t structure */ else { int flags; rtl_critical(flags); switch (mq->status) { case RT_MQ_EMPTY: /* q empty -- this task must wait */ { if (wait == RT_NO_WAIT) ret = -EAGAIN; /* can't dequeue it -- just report error */ else /* wait is allowed */ { 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 = mq->wait_list; if (to_add->next != NULL) to_add->next->prev = to_add; mq->wait_list = to_add; /* indicate which mq the task is blocked at */ ((RT_TASK_IPC *)rtl_current)->mq_at = mq; if (wait == RT_WAIT_FOREVER) rt_task_suspend(rtl_current); /* suspend until receive */ else { /* assume call timed out. If this is not the case, */ /* rt_mq_send() will clear this flag */ ((RT_TASK_IPC *)rtl_current)->timed_out = 1; /* delay until either send occurs or timeout occurs */ rt_task_delay(wait); if (((RT_TASK_IPC *)rtl_current)->timed_out) { /* timed out -- undo everything and return */ unlink_mq_task(to_add, mq); ret = -ETIME; break; } } /* when again allowed to run, enqueue the data */ dequeue(mq, msg); /* finally, dequeue the data */ } break; } case RT_MQ_FULL: /* q full -- this operation might unblock a task */ { RT_TASK_ENTRY *t, *to_run; dequeue(mq, msg); /* first, go ahead and dequeue the data */ /* find the waiting task with the highest priority */ /* 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=mq->wait_list, to_run=NULL ; t!=NULL ; t=t->next) if (to_run == NULL || GET_PRIO(t->task) < GET_PRIO(to_run->task)) to_run = t; if (to_run != NULL) { /* remove the task to be run from the wait_list */ unlink_mq_task(to_run, mq); /* mark that task as no longer waiting at mq */ ((RT_TASK_IPC *)(to_run->task))->mq_at = NULL; /* rt_mq_send() will return because of a receive, not */ /* because of a timeout */ ((RT_TASK_IPC *)(to_run->task))->timed_out = 0; rt_task_wakeup(to_run->task); } break; } case RT_MQ_NEITHER: /* data is present -- take it out */ dequeue(mq, msg); break; } rtl_end_critical(flags); } return ret;}typedef struct{ rt_sem_t sem;} RT_IPC_FIFO; /* structure holding rt_ipc rt-fifo-specific data */static RT_IPC_FIFO ipc_fifos[IPC_RTF_NO]; /* rt_ipc-specific fifo data *//************************************************************************* * rtf_ipc_handler -- handler for read/write operations on rt_ipc rt-fifo * * Called when a read or write operation is performed on an rt_ipc rt-fifo * by a Linux process. * * Returns 0. *************************************************************************/static int rtf_ipc_handler(unsigned int fifo){ return rt_sem_post(&ipc_fifos[fifo].sem);}/************************************************************************* * rtf_ipc_create -- create an rt_ipc rt-fifo * * Creates the rt_ipc rt-fifo 'fifo'. This has the same capabilities as * the standard RT-Linux rt-fifos but adds blocking. 'size' is the size * of the fifo in bytes. If 'rtl_to_linux' is 1, the fifo is used for * transferring data from RT-Linux tasks to a Linux process. If 'rtl_to_linux' * is 0, the fifo is used for transferring data from a Linux process to * one or more RT-Linux tasks. * * Returns 0 if successful, -ENODEV if 'fifo' is not less than IPC_RTF_NO * and RTF_NO, -EBUSY if 'fifo' is in use, or -ENOMEM if 'size' bytes could * not be allocated. *************************************************************************/int rtf_ipc_create(unsigned int fifo, int size, int rtl_to_linux){ int ret = 0; if (fifo >= IPC_RTF_NO) ret = -ENODEV; else if ((ret = rtf_create(fifo, size)) >= 0) { /* init the semaphores -- initially no data is ready to receive, but */ /* data can be sent */ if ((ret = rt_sem_init(&ipc_fifos[fifo].sem, RT_SEM_BINARY, rtl_to_linux)) >= 0) ret = rtf_create_handler(fifo, &rtf_ipc_handler); } return ret;}/************************************************************************* * rtf_ipc_destroy -- destroy an rt_ipc rt-fifo * * Removes the rt_ipc rt-fifo 'fifo' previously created with rt_ipc_create(). * * Returns 0 if successful, -EINVAL if 'fifo' is not a valid fifo identifier. *************************************************************************/int rtf_ipc_destroy(unsigned int fifo){ int ret; if ((ret = rt_sem_destroy(&ipc_fifos[fifo].sem)) >= 0) ret = rtf_destroy(fifo); return ret;}/************************************************************************* * rtf_receive -- get data from an rt_ipc rt-fifo * * Gets data from the rt-fifo 'fifo'. The data, up to size 'count', is put * into 'buf'. If 'timeout' is RT_NO_WAIT, the function returns immediately * even if 'count' bytes are not available. If 'timeout' is RT_WAIT_FOREVER, * the function blocks until 'count' bytes are available. If 'timeout' is * any other value, it represents the time at which the function will return * with a timeout after unsuccessfully waiting for data. In any case, as * many bytes as possible are returned, even if a timeout occurs or * RT_NO_WAIT is specified. * * Returns -ENODEV if 'fifo' is greater than or equal to RTF_NO, -EINVAL if * 'fifo' is not a valid fifo identifier. If the return value is greater * than or equal to zero, it represents the number of bytes received. * This might be less than 'count' if the function timed out or RT_NO_WAIT * was specified and less than 'count' bytes were available. *************************************************************************/int rtf_receive(unsigned int fifo, void *buf, int count, RTIME timeout){ int ret = 0, bytes_still_to_get=count; for ( ; bytes_still_to_get > 0 ; ) { if ((ret = rtf_get(fifo, buf, bytes_still_to_get)) < 0) break; bytes_still_to_get -= ret; buf += ret; if (bytes_still_to_get != 0) if ((ret = rt_sem_wait(&ipc_fifos[fifo].sem, timeout)) < 0) break; } if (ret == -ETIME || ret == -EAGAIN) return count - bytes_still_to_get; else if (ret < 0) return ret; else { /* Note the questionable assumption -- I signal that data is available */ /* for receiving any time rtf_receive() returns successfully. Thus the */ /* assumption is that if 'count' bytes are available, there must be more. */ /* Obviously wrong if the fifo has exactly 'count' bytes available when */ /* called. I have to make this assumption because I have no way of */ /* knowing how many bytes are available in the fifo. The only effect of */ /* this is that a task waiting on the semaphore may go one more time */ /* through the loop before again waiting at the semaphore. */ if ((ret = rt_sem_post(&ipc_fifos[fifo].sem)) < 0) return ret; else return count; }}/************************************************************************* * rtf_send -- send data to an rt_ipc rt-fifo * * Sends data to the rt-fifo 'fifo'. The data, of size 'count', is taken * from 'buf'. If 'timeout' is RT_NO_WAIT, the function returns immediately * even if 'count' bytes cannot be sent. If 'timeout' is RT_WAIT_FOREVER, * the function blocks until 'count' bytes can be sent. If 'timeout' is * any other value, it represents the time at which the function will return * with a timeout after unsuccessfully waiting to send the data. If * rtf_send() cannot send the entire block, no data is sent. * * Returns -ENODEV if 'fifo' is greater than or equal to RTF_NO, -EINVAL if * 'fifo' is not a valid fifo identifier. If the return value is greater * than or equal to zero, it represents the number of bytes sent. * This might be zero if the function timed out or RT_NO_WAIT * was specified and less than 'count' bytes could be sent. *************************************************************************/int rtf_send(unsigned int fifo, void *buf, int count, RTIME timeout){ int ret = 0, bytes_still_to_send=count; for ( ; bytes_still_to_send > 0 ; ) { /* Note the asymmetry between rtf_send() and rtf_receive() due to the */ /* fact that rtf_put() returns -ENOSPC if it cannot place all bytes on */ /* the fifo, whereas rtf_get() returns as many bytes as it can, even if */ /* it cannot return all bytes requested. Also, rtf_put() returns the */ /* number of bytes not written, whereas rtf_get() returns the number of */ /* bytes successfully read. */ ret = rtf_put(fifo, buf, bytes_still_to_send); if (ret == -ENOSPC) ret = 0; else if (ret < 0) break; /* correct for fact that ret is number of bytes NOT yet sent */ ret = (bytes_still_to_send - ret); bytes_still_to_send -= ret; buf += ret; if (bytes_still_to_send != 0) if ((ret = rt_sem_wait(&ipc_fifos[fifo].sem, timeout)) < 0) break; } if (ret == -ETIME || ret == -EAGAIN) return count - bytes_still_to_send; else if (ret < 0) return ret; else { /* Note the questionable assumption -- I signal that space is available */ /* for sending any time rtf_send() returns successfully. Thus the */ /* assumption is that if 'count' bytes could be sent, there must be room */ /* for more. Obviously wrong if the fifo has exactly 'count' bytes empty */ /* when called. I have to make this assumption because I have no way of */ /* knowing how many bytes are available in the fifo. The only effect of */ /* this is that a task waiting on the semaphore may go one more time */ /* through the loop before again waiting at the semaphore. */ if ((ret = rt_sem_post(&ipc_fifos[fifo].sem)) < 0) return ret; else return count; }}int init_module(void){ printk("rt_ipc V" IPC_VERSION " -- IPC primitives for use with Real-Time Linux\n"); printk("Copyright (C) 1997 Jerry Epplin. All rights reserved.\n"); return 0;}void cleanup_module(void){ printk("rt_ipc -- removed.\n");}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -