1 / 32

Real-Time Systems Inter-Process Communication in RT-Linux Professor : Wei-Kuan Shih

Real-Time Systems Inter-Process Communication in RT-Linux Professor : Wei-Kuan Shih Student : g914344 陸婉珍 g914367 洪吉亮. Introduction. rt_ipc is a Linux loadable module for use with Real-Time Linux

Download Presentation

Real-Time Systems Inter-Process Communication in RT-Linux Professor : Wei-Kuan Shih

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Real-Time Systems Inter-Process Communication in RT-Linux Professor : Wei-Kuan Shih Student : g914344 陸婉珍 g914367 洪吉亮

  2. Introduction • rt_ipc is a Linux loadable module for use with Real-Time Linux • Currently rt_ipc provides semaphores (binary and counting), message queues, and an enhancement to the RT-FIFO mechanism that provides blocking and timeouts

  3. prev prev prev next next next task task task Task List Data Structure • RT_TASK_ENTRY(wait list)

  4. int magic int val RT_SEMTYPE type RT_TASK_ENTRY wait_list Semaphore Data Structure • rt_sem_t

  5. magic val type wait_list FIFO Data Structure • RT_IPC_FIFO rt_sem_tsem

  6. int magic char q int msg_size int max_msgs char f char r RT_MQ_STATUS status RT_TASK_ENTRY wait_list Message Queue Data Structure • rt_mq_t

  7. RT_TASK rtl_task magic q int magic msg_size RT_TASK_ENTRY rte max_msgs rt_sem_t sem_at f rt_mq_t mq_at r magic int timed_out status val wait_list type wait_list RT-Linux Task Data Structure for IPC • RT_TASK_IPC

  8. rt_task_ipc_init(rt_ipc) • The function initializes some rt_ipc variables int rt_task_ipc_init(RT_TASK_IPC *task, void (*fn)(int data), int data, int stack_size, int priority) { int ret; task->sem_at = NULL; task->magic = RT_TASK_IPC_MAGIC; ret = rt_task_init(MAKE_RT_TASK(task), fn, data, stack_size, priority); if (ret < 0) { return ret; } (*MAKE_RT_TASK(task))->user[IPC_DATA_INDEX] = task; return 0; } This allows you to check at run time whether (a) a structure has been clobbered, or (b) you've passed the wrong structure to a routine Returns 0 if successful, -EINVAL if the 'task' structure is already in * use by another task, or -ENOMEM if a memory allocation error occurred

  9. rt_task_ipc_delete(rt_ipc) • The function removes the task from any semaphore or message queue int rt_task_ipc_delete(RT_TASK_IPC *task) { int ret = 0; if (task->magic != RT_TASK_IPC_MAGIC) ret = EINVAL; else { int flags; rtl_critical(flags); if (task->sem_at != NULL) unlink_sem_task(&(task->rte), task->sem_at);

  10. rt_task_ipc_delete(rt_ipc) (cont.) else if (task->mq_at != NULL) unlink_mq_task(&(task->rte), task->mq_at); rtl_end_critical(flags); ret = rt_task_delete(MAKE_RT_TASK(task)); } return ret; }

  11. rt_task_delay • The function delays the calling task until the time specified in ‘duration’ int rt_task_delay(RTIME duration) { int ret = 0; int flags; rtl_critical(flags); pthread_self()->period = 0; RTL_MARK_SUSPENDED(pthread_self()); __rtl_setup_timeout(pthread_self(), HRT_FROM_8254(duration)); rtl_schedule(); rtl_end_critical(flags); return ret; } mark the task as delayed set the time at which execution may resume

  12. rt_sem_init • The function initializes a real-time semaphore 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; else { sem->magic = RT_SEM_MAGIC; sem->val = init_val; sem->type = type; sem->wait_list = NULL; } return ret; } binary sem must have 0 or 1

  13. rt_sem_destroy • The function removes a real-time semaphore previously created with rt_sem_init() int rt_sem_destroy(rt_sem_t *sem) { int ret = 0; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; else while (sem->val < 0) rt_sem_post(sem); return ret; } unblock any tasks blocked on this sem

  14. rt_mq_init • initialize a real-time message queue int rt_mq_init(rt_mq_t *mq, int max_msgs, int msg_size) { int ret = 0; if (max_msgs <= 0 || msg_size < 0) ret = -EINVAL; /* must be positive */ else { mq->magic = RT_MQ_MAGIC; mq->wait_list = NULL; mq->max_msgs = max_msgs; mq->msg_size = msg_size; if ((mq->q = kmalloc(max_msgs * msg_size, GFP_KERNEL)) == NULL) ret = -ENOMEM; else { mq->status = RT_MQ_EMPTY; mq->f = mq->r = mq->q; /* initialize queue pointers */ } } return ret; }

  15. rt_mq_destroy • remove a real-time message queue int rt_mq_destroy(rt_mq_t *mq) { int ret = 0; if (mq->magic != RT_MQ_MAGIC) ret = -EINVAL; else { /* unblock any tasks blocked on this message queue */ while (rt_mq_send(mq, NULL, RT_MQ_NORMAL, RT_NO_WAIT) != 0) ; while (rt_mq_receive(mq, NULL, RT_NO_WAIT) != 0) ; kfree_s(mq->q, mq->max_msgs * mq->msg_size); } return ret; }

  16. unlink_sem_task • The function 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; }

  17. unlink_mq_task • The function 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; }

  18. rtf_ipc_create • The function creates an rt_ipc rt-fifo 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) { 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; } init the semaphores -- initially no data is ready to receive, but data can be sent

  19. rtf_ipc_destroy • The function destroy an rt_ipc rt-fifo 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; }

  20. Semaphore Operation: Wait (Blocking)-1 int rt_sem_wait(rt_sem_t *sem, RTIME timeout) { int ret = 0; int flags; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; else { rtl_critical(flags); if (sem->val <= 0) { … } else --sem->val; rtl_end_critical(flags); } return ret; } invalid rt_sem_t structure sem not available -- task must wait

  21. Semaphore Operation: Wait (Blocking)-2 RT_TASK_ENTRY *to_add = &(((RT_TASK_IPC *)rtl_current)->rte); 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; ((RT_TASK_IPC *)rtl_current)->sem_at = sem; --sem->val; if (timeout == RT_WAIT_FOREVER) rt_task_suspend(rtl_current); else { ((RT_TASK_IPC *)rtl_current)->timed_out = 1; rt_task_delay(timeout); if (((RT_TASK_IPC *)rtl_current)->timed_out) { unlink_sem_task(to_add, sem); ++sem->val; ret = -ETIME; } } Put the task into the head of the wait list and mark the task as blocked by the semaphore Block the task

  22. Semaphore Operation: Wait (Unblocking) • The function returns immediately whether or not the semaphore is available int rt_sem_trywait(rt_sem_t *sem) { int ret = 0; int flags; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; else { rtl_critical(flags); if (sem->val <= 0) ret = -EAGAIN; else --sem->val; rtl_end_critical(flags); } return ret; } invalid rt_sem_t structure sem not available -- task must wait

  23. Semaphore Operation: Signal(Post) int rt_sem_post(rt_sem_t *sem) { int ret = 0; int flags; if (sem->magic != RT_SEM_MAGIC) ret = -EINVAL; else { … } return ret; } check to see if this semaphore is valid

  24. Semaphore Operation: Signal(Post) (cont.) There’re one or more tasks waiting for this semaphore, the task with the highest priority is chosen RT_TASK_ENTRY *to_run = NULL; rtl_critical(flags); if (sem->val < 0) { RT_TASK_ENTRY *t; 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; unlink_sem_task(to_run, sem); ((RT_TASK_IPC *)(to_run->task))->sem_at = NULL; } if (sem->val < 1 || sem->type == RT_SEM_COUNTING) ++sem->val; if (to_run != NULL) { ((RT_TASK_IPC *)(to_run->task))->timed_out = 0; rt_task_wakeup(to_run->task); } rtl_end_critical(flags); Wake up the chosen task

  25. FIFO Operation: get data • The function gets data from the rt-fifo 'fifo'. The data, up to size 'count', is put * into ‘buf’ 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 { if ((ret = rt_sem_post(&ipc_fifos[fifo].sem)) < 0) return ret; else return count; } } Exit this loop on read error Upon being pre-empted, waiting for being woken up. Exit this loop when timeout

  26. FIFO Operation: send data • The function sends data to the rt-fifo 'fifo'. The data, of size ‘count‘, is taken from ‘buf’ and put to ‘fifo’. If the entire block of data can’t be sent, then no data is 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 ; ) { ret = rtf_put(fifo, buf, bytes_still_to_send); if (ret == -ENOSPC) ret = 0; else if (ret < 0) break; 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 rtf_put() can’t place all bytes on the fifo, then return 0, meaning that no data is sent to fifo. Other error codes is returned according to different error conditions Do this due to the fact that rtf_put() returns the number of bytes not written Upon being pre-empted, waiting for being woken up. Exit this loop when timeout

  27. FIFO Operation: send data (cont.) if (ret == -ETIME || ret == -EAGAIN) return count - bytes_still_to_send; else if (ret < 0) return ret; else { if ((ret = rt_sem_post(&ipc_fifos[fifo].sem)) < 0) return ret; else return count; } }

  28. Message Queue Operation: enqueue • The function enqueues a block of data on the queue 'mq' with priority 'prio‘ static void enqueue(rt_mq_t *mq, char *msg, RT_MQ_PRIO prio) { if (prio == RT_MQ_NORMAL) { if (msg != NULL) memcpy(mq->r, msg, mq->msg_size); if ((mq->r += mq->msg_size) == mq->q + mq->msg_size * mq->max_msgs) mq->r = mq->q; }else{ if (mq->f == mq->q) mq->f = mq->q + mq->msg_size * (mq->max_msgs- 1) ; else mq->f -= mq->msg_size; if (msg != NULL) memcpy(mq->f, msg, mq->msg_size); } if (mq->f == mq->r) mq->status = RT_MQ_FULL; else mq->status = RT_MQ_NEITHER; } check for wraparound check for wraparound queue is now full

  29. Message Queue Operation: dequeue • The function dequeues a block of data from the queue 'mq‘ static void dequeue(rt_mq_t *mq, char *msg) { if (msg != NULL) memcpy(msg, mq->f, mq->msg_size); if ((mq->f += mq->msg_size) == mq->q + mq->msg_size * mq->max_msgs) mq->f = mq->q; if (mq->r == mq->f) mq->status = RT_MQ_EMPTY; else mq->status = RT_MQ_NEITHER; } check for wraparound queue is now empty

  30. Message Queue Operation: send • The function enqueues the data 'msg' on the message queue 'mq'. The data is assumed * to be of the size with which rt_mq_init() was called int rt_mq_send(rt_mq_t *mq, char *msg, RT_MQ_PRIO prio, RTIME wait) { int ret = 0; if (mq->magic != RT_MQ_MAGIC) ret = -EINVAL; else { int flags; rtl_critical(flags); switch (mq->status) { … enter the critical section and operate according to the status of the message queue

  31. Message Queue Operation: send(cont.) Immediate return case RT_MQ_FULL: { if (wait == RT_NO_WAIT) ret = -EAGAIN; else { RT_TASK_ENTRY *to_add = &(((RT_TASK_IPC *)rtl_current)->rte); 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; ((RT_TASK_IPC *)rtl_current)->mq_at = mq; if (wait == RT_WAIT_FOREVER) rt_task_suspend(rtl_current); else { ((RT_TASK_IPC *)rtl_current)->timed_out = 1; rt_task_delay(wait); if (((RT_TASK_IPC *)rtl_current)->timed_out) { unlink_mq_task(to_add, mq); ret = -ETIME; break; } } enqueue(mq, msg, prio); } break; } put task on wait_list indicate which mq the task is blocked at suspend until receive If waiting time is unbounded, then the task is suspended until being unblocked. Otherwise wait for unblocking until timeout. If timeout, then remove the this task from the waiting list The task is unblocked and the data is enqueued

  32. Message Queue Operation: send(cont.) case RT_MQ_EMPTY: { RT_TASK_ENTRY *t, *to_run; enqueue(mq, msg, prio); 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) { unlink_mq_task(to_run, mq); ((RT_TASK_IPC *)(to_run->task))->mq_at = NULL; ((RT_TASK_IPC *)(to_run->task))->timed_out = 0; rt_task_wakeup(to_run->task); } break; } case RT_MQ_NEITHER: enqueue(mq, msg, prio); break; } rtl_end_critical(flags); } return ret; }

More Related