Subversion Repositories HelenOS-historic

Rev

Rev 1005 | Rev 1050 | 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.     call->sender = TASK;
  75. }
  76.  
  77. /** Deallocate call stracuture */
  78. void ipc_call_free(call_t *call)
  79. {
  80.     slab_free(ipc_call_slab, call);
  81. }
  82.  
  83. /** Initialize answerbox structure
  84.  */
  85. void ipc_answerbox_init(answerbox_t *box)
  86. {
  87.     mutex_initialize(&box->mutex);
  88.     condvar_initialize(&box->cv);
  89.     list_initialize(&box->connected_phones);
  90.     list_initialize(&box->calls);
  91.     list_initialize(&box->dispatched_calls);
  92.     list_initialize(&box->answers);
  93.     box->task = TASK;
  94. }
  95.  
  96. /** Initialize phone structure and connect phone to naswerbox
  97.  */
  98. void ipc_phone_init(phone_t *phone, answerbox_t *box)
  99. {
  100.     spinlock_initialize(&phone->lock, "phone_lock");
  101.    
  102.     phone->callee = box;
  103.  
  104.     mutex_lock(&box->mutex);
  105.     list_append(&phone->list, &box->connected_phones);
  106.     mutex_unlock(&box->mutex);
  107. }
  108.  
  109. /** Disconnect phone from answerbox */
  110. void ipc_phone_destroy(phone_t *phone)
  111. {
  112.     answerbox_t *box = phone->callee;
  113.    
  114.     ASSERT(box);
  115.  
  116.     mutex_lock(&box->mutex);
  117.     list_remove(&phone->list);
  118.     mutex_unlock(&box->mutex);
  119. }
  120.  
  121. /** Helper function to facilitate synchronous calls */
  122. void ipc_call_sync(phone_t *phone, call_t *request)
  123. {
  124.     answerbox_t sync_box;
  125.  
  126.     ipc_answerbox_init(&sync_box);
  127.  
  128.     /* We will receive data on special box */
  129.     request->callerbox = &sync_box;
  130.  
  131.     ipc_call(phone, request);
  132.     ipc_wait_for_call(&sync_box, 0);
  133. }
  134.  
  135. /** Send a asynchronous request using phone to answerbox
  136.  *
  137.  * @param phone Phone connected to answerbox
  138.  * @param request Request to be sent
  139.  */
  140. void ipc_call(phone_t *phone, call_t *request)
  141. {
  142.     answerbox_t *box = phone->callee;
  143.  
  144.     ASSERT(box);
  145.  
  146.     mutex_lock(&box->mutex);
  147.     list_append(&request->list, &box->calls);
  148.     mutex_unlock(&box->mutex);
  149.     condvar_signal(&box->cv);
  150. }
  151.  
  152. /** Answer message back to phone
  153.  *
  154.  * @param box Answerbox that is answering the message
  155.  * @param request Modified request that is being sent back
  156.  */
  157. void ipc_answer(answerbox_t *box, call_t *request)
  158. {
  159.     answerbox_t *callerbox = request->callerbox;
  160.  
  161.     request->flags |= IPC_CALL_ANSWERED;
  162.  
  163.     mutex_lock(&box->mutex);
  164.     list_remove(&request->list);
  165.     mutex_unlock(&box->mutex);
  166.  
  167.     mutex_lock(&callerbox->mutex);
  168.     list_append(&request->list, &callerbox->answers);
  169.     mutex_unlock(&callerbox->mutex);
  170.     condvar_signal(&callerbox->cv);
  171. }
  172.  
  173. /** Wait for phone call
  174.  *
  175.  * @return Recived message address
  176.  * - to distinguish between call and answer, look at call->flags
  177.  */
  178. call_t * ipc_wait_for_call(answerbox_t *box, int flags)
  179. {
  180.     call_t *request;
  181.  
  182.     mutex_lock(&box->mutex);
  183.     while (1) {
  184.         if (!list_empty(&box->answers)) {
  185.             /* Handle asynchronous answers */
  186.             request = list_get_instance(box->answers.next, call_t, list);
  187.             list_remove(&request->list);
  188.         } else if (!list_empty(&box->calls)) {
  189.             /* Handle requests */
  190.             request = list_get_instance(box->calls.next, call_t, list);
  191.             list_remove(&request->list);
  192.             /* Append request to dispatch queue */
  193.             list_append(&request->list, &box->dispatched_calls);
  194.         } else {
  195.             if (!(flags & IPC_WAIT_NONBLOCKING)) {
  196.                 /* Wait for event to appear */
  197.                 condvar_wait(&box->cv, &box->mutex);
  198.                 continue;
  199.             }
  200.             request = NULL;
  201.         }
  202.         break;
  203.     }
  204.     mutex_unlock(&box->mutex);
  205.     return request;
  206. }
  207.  
  208. /** Initilize ipc subsystem */
  209. void ipc_init(void)
  210. {
  211.     ipc_call_slab = slab_cache_create("ipc_call",
  212.                       sizeof(call_t),
  213.                       0,
  214.                       NULL, NULL, 0);
  215. }
  216.