Subversion Repositories HelenOS

Rev

Rev 980 | Rev 1027 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2006 Ondrej Palkovsky
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /* Lock ordering
  30.  *
  31.  * First the answerbox, then the phone
  32.  */
  33.  
  34. #include <synch/condvar.h>
  35. #include <synch/mutex.h>
  36. #include <ipc/ipc.h>
  37. #include <errno.h>
  38. #include <mm/slab.h>
  39. #include <arch.h>
  40. #include <proc/task.h>
  41. #include <memstr.h>
  42. #include <debug.h>
  43.  
  44. #include <print.h>
  45. #include <proc/thread.h>
  46.  
  47. /* Open channel that is assigned automatically to new tasks */
  48. answerbox_t *ipc_phone_0 = NULL;
  49.  
  50. static slab_cache_t *ipc_call_slab;
  51.  
  52. /** Allocate & initialize call structure
  53.  *
  54.  * The call is initialized, so that the reply will be directed
  55.  * to TASK->answerbox
  56.  */
  57. call_t * ipc_call_alloc(void)
  58. {
  59.     call_t *call;
  60.  
  61.     call = slab_alloc(ipc_call_slab, 0);
  62.     memsetb((__address)call, sizeof(*call), 0);
  63.     call->callerbox = &TASK->answerbox;
  64.     call->sender = TASK;
  65.  
  66.     return call;
  67. }
  68.  
  69. /** Initialize allocated call */
  70. void ipc_call_init(call_t *call)
  71. {
  72.     call->callerbox = &TASK->answerbox;
  73.     call->flags = IPC_CALL_STATIC_ALLOC;
  74. }
  75.  
  76. /** Deallocate call stracuture */
  77. void ipc_call_free(call_t *call)
  78. {
  79.     slab_free(ipc_call_slab, call);
  80. }
  81.  
  82. /** Initialize answerbox structure
  83.  */
  84. void ipc_answerbox_init(answerbox_t *box)
  85. {
  86.     mutex_initialize(&box->mutex);
  87.     condvar_initialize(&box->cv);
  88.     list_initialize(&box->connected_phones);
  89.     list_initialize(&box->calls);
  90.     list_initialize(&box->dispatched_calls);
  91.     list_initialize(&box->answers);
  92. }
  93.  
  94. /** Initialize phone structure and connect phone to naswerbox
  95.  */
  96. void ipc_phone_init(phone_t *phone, answerbox_t *box)
  97. {
  98.     spinlock_initialize(&phone->lock, "phone_lock");
  99.    
  100.     phone->callee = box;
  101.  
  102.     mutex_lock(&box->mutex);
  103.     list_append(&phone->list, &box->connected_phones);
  104.     mutex_unlock(&box->mutex);
  105. }
  106.  
  107. /** Disconnect phone from answerbox */
  108. void ipc_phone_destroy(phone_t *phone)
  109. {
  110.     answerbox_t *box = phone->callee;
  111.    
  112.     ASSERT(box);
  113.  
  114.     mutex_lock(&box->mutex);
  115.     list_remove(&phone->list);
  116.     mutex_unlock(&box->mutex);
  117. }
  118.  
  119. /** Helper function to facilitate synchronous calls */
  120. void ipc_call_sync(phone_t *phone, call_t *request)
  121. {
  122.     answerbox_t sync_box;
  123.  
  124.     ipc_answerbox_init(&sync_box);
  125.  
  126.     /* We will receive data on special box */
  127.     request->callerbox = &sync_box;
  128.  
  129.     ipc_call(phone, request);
  130.     ipc_wait_for_call(&sync_box, 0);
  131. }
  132.  
  133. /** Send a asynchronous request using phone to answerbox
  134.  *
  135.  * @param phone Phone connected to answerbox
  136.  * @param request Request to be sent
  137.  */
  138. void ipc_call(phone_t *phone, call_t *request)
  139. {
  140.     answerbox_t *box = phone->callee;
  141.  
  142.     ASSERT(box);
  143.  
  144.     mutex_lock(&box->mutex);
  145.     list_append(&request->list, &box->calls);
  146.     mutex_unlock(&box->mutex);
  147.     condvar_signal(&box->cv);
  148. }
  149.  
  150. /** Answer message back to phone
  151.  *
  152.  * @param box Answerbox that is answering the message
  153.  * @param request Modified request that is being sent back
  154.  */
  155. void ipc_answer(answerbox_t *box, call_t *request)
  156. {
  157.     answerbox_t *callerbox = request->callerbox;
  158.  
  159.     request->flags |= IPC_CALL_ANSWERED;
  160.  
  161.     mutex_lock(&box->mutex);
  162.     list_remove(&request->list);
  163.     mutex_unlock(&box->mutex);
  164.  
  165.     mutex_lock(&callerbox->mutex);
  166.     list_append(&request->list, &callerbox->answers);
  167.     mutex_unlock(&callerbox->mutex);
  168.     condvar_signal(&callerbox->cv);
  169. }
  170.  
  171. /** Wait for phone call
  172.  *
  173.  * @return Recived message address
  174.  * - to distinguish between call and answer, look at call->flags
  175.  */
  176. call_t * ipc_wait_for_call(answerbox_t *box, int flags)
  177. {
  178.     call_t *request;
  179.  
  180.     mutex_lock(&box->mutex);
  181.     while (1) {
  182.         if (!list_empty(&box->answers)) {
  183.             /* Handle asynchronous answers */
  184.             request = list_get_instance(box->answers.next, call_t, list);
  185.             list_remove(&request->list);
  186.         } else if (!list_empty(&box->calls)) {
  187.             /* Handle requests */
  188.             request = list_get_instance(box->calls.next, call_t, list);
  189.             list_remove(&request->list);
  190.             /* Append request to dispatch queue */
  191.             list_append(&request->list, &box->dispatched_calls);
  192.         } else {
  193.             if (!(flags & IPC_WAIT_NONBLOCKING)) {
  194.                 /* Wait for event to appear */
  195.                 condvar_wait(&box->cv, &box->mutex);
  196.                 continue;
  197.             }
  198.             request = NULL;
  199.         }
  200.         break;
  201.     }
  202.     mutex_unlock(&box->mutex);
  203.     return request;
  204. }
  205.  
  206. /** Initilize ipc subsystem */
  207. void ipc_init(void)
  208. {
  209.     ipc_call_slab = slab_cache_create("ipc_call",
  210.                       sizeof(call_t),
  211.                       0,
  212.                       NULL, NULL, 0);
  213. }
  214.