Subversion Repositories HelenOS-historic

Rev

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