⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rt_ipc.c

📁 fsmlabs的real time linux的内核
💻 C
📖 第 1 页 / 共 3 页
字号:
 * 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 + -