Subversion Repositories HelenOS

Rev

Rev 955 | Rev 965 | 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/waitq.h>
  35. #include <ipc/ipc.h>
  36. #include <errno.h>
  37. #include <mm/slab.h>
  38. #include <arch.h>
  39. #include <proc/task.h>
  40. #include <memstr.h>
  41. #include <debug.h>
  42.  
  43. #include <print.h>
  44. #include <proc/thread.h>
  45.  
  46. answerbox_t *ipc_central_box;
  47.  
  48. static slab_cache_t *ipc_call_slab;
  49.  
  50. /** Allocate & initialize call structure
  51.  *
  52.  * The call is initialized, so that the reply will be directed
  53.  * to TASK->answerbox
  54.  */
  55. call_t * ipc_call_alloc(void)
  56. {
  57.     call_t *call;
  58.  
  59.     call = slab_alloc(ipc_call_slab, 0);
  60.     memsetb((__address)call, sizeof(*call), 0);
  61.     call->callerbox = &TASK->answerbox;
  62.  
  63.     return call;
  64. }
  65.  
  66. /** Deallocate call stracuture */
  67. void ipc_call_free(call_t *call)
  68. {
  69.     slab_free(ipc_call_slab, call);
  70. }
  71.  
  72. /** Initialize answerbox structure
  73.  */
  74. void ipc_answerbox_init(answerbox_t *box)
  75. {
  76.     spinlock_initialize(&box->lock, "abox_lock");
  77.     waitq_initialize(&box->wq);
  78.     list_initialize(&box->connected_phones);
  79.     list_initialize(&box->calls);
  80.     list_initialize(&box->dispatched_calls);
  81.     list_initialize(&box->answers);
  82. }
  83.  
  84. /** Initialize phone structure and connect phone to naswerbox
  85.  */
  86. void ipc_phone_init(phone_t *phone, answerbox_t *box)
  87. {
  88.     spinlock_initialize(&phone->lock, "phone_lock");
  89.    
  90.     phone->callee = box;
  91.     spinlock_lock(&box->lock);
  92.     list_append(&phone->list, &box->connected_phones);
  93.     spinlock_unlock(&box->lock);
  94. }
  95.  
  96. /** Disconnect phone from answerbox */
  97. void ipc_phone_destroy(phone_t *phone)
  98. {
  99.     answerbox_t *box = phone->callee;
  100.    
  101.     ASSERT(box);
  102.  
  103.     spinlock_lock(&box->lock);
  104.     list_remove(&phone->list);
  105.     spinlock_unlock(&box->lock);
  106. }
  107.  
  108. /** Helper function to facilitate synchronous calls */
  109. void ipc_call_sync(phone_t *phone, call_t *request)
  110. {
  111.     answerbox_t sync_box;
  112.  
  113.     ipc_answerbox_init(&sync_box);
  114.  
  115.     /* We will receive data on special box */
  116.     request->callerbox = &sync_box;
  117.  
  118.     ipc_call(phone, request);
  119.     ipc_wait_for_call(&sync_box, 0);
  120. }
  121.  
  122. /** Send a asynchronous request using phone to answerbox
  123.  *
  124.  * @param phone Phone connected to answerbox
  125.  * @param request Request to be sent
  126.  */
  127. void ipc_call(phone_t *phone, call_t *request)
  128. {
  129.     answerbox_t *box = phone->callee;
  130.  
  131.     ASSERT(box);
  132.  
  133.     spinlock_lock(&box->lock);
  134.     list_append(&request->list, &box->calls);
  135.     spinlock_unlock(&box->lock);
  136.     waitq_wakeup(&box->wq, 0);
  137. }
  138.  
  139. /** Answer message back to phone
  140.  *
  141.  * @param box Answerbox that is answering the message
  142.  * @param request Modified request that is being sent back
  143.  */
  144. void ipc_answer(answerbox_t *box, call_t *request)
  145. {
  146.     answerbox_t *callerbox = request->callerbox;
  147.  
  148.     request->flags |= IPC_CALL_ANSWERED;
  149.  
  150.     spinlock_lock(&box->lock);
  151.     spinlock_lock(&callerbox->lock);
  152.  
  153.     list_remove(&request->list);
  154.     list_append(&request->list, &callerbox->answers);
  155.     waitq_wakeup(&callerbox->wq, 0);
  156.  
  157.     spinlock_unlock(&callerbox->lock);
  158.     spinlock_unlock(&box->lock);
  159. }
  160.  
  161. /** Wait for phone call
  162.  *
  163.  * @return Recived message address
  164.  * - to distinguish between call and answer, look at call->flags
  165.  */
  166. call_t * ipc_wait_for_call(answerbox_t *box, int flags)
  167. {
  168.     call_t *request;
  169.  
  170.     if ((flags & IPC_WAIT_NONBLOCKING)) {
  171.         if (waitq_sleep_timeout(&box->wq,SYNCH_NO_TIMEOUT,SYNCH_NON_BLOCKING) == ESYNCH_WOULD_BLOCK)
  172.             return 0;
  173.     } else {
  174.         waitq_sleep(&box->wq);
  175.     }
  176.  
  177.  
  178.     // TODO - might need condition variable+mutex if we want to support
  179.     // removing of requests from queue before dispatch
  180.     spinlock_lock(&box->lock);
  181.     /* Handle answers first */
  182.     if (!list_empty(&box->answers)) {
  183.         request = list_get_instance(box->answers.next, call_t, list);
  184.         list_remove(&request->list);
  185.     } else {
  186.         ASSERT (! list_empty(&box->calls));
  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.     }
  192.     spinlock_unlock(&box->lock);
  193.  
  194.     return request;
  195. }
  196.  
  197. /** Initilize ipc subsystem */
  198. void ipc_init(void)
  199. {
  200.     ipc_call_slab = slab_cache_create("ipc_call",
  201.                       sizeof(call_t),
  202.                       0,
  203.                       NULL, NULL, 0);
  204. }
  205.  
  206. static void ipc_phonecompany_thread(void *data)
  207. {
  208.     call_t *call;
  209.  
  210.     printf("Phone company started.\n");
  211.     while (1) {
  212.         call = ipc_wait_for_call(&TASK->answerbox, 0);
  213.         printf("Received phone call - %P %P\n",
  214.                call->data[0], call->data[1]);
  215.         call->data[0] = 0xbabaaaee;;
  216.         call->data[1] = 0xaaaaeeee;
  217.         ipc_answer(&TASK->answerbox, call);
  218.         printf("Call answered.\n");
  219.     }
  220. }
  221.  
  222. void ipc_create_phonecompany(void)
  223. {
  224.     thread_t *t;
  225.    
  226.     if ((t = thread_create(ipc_phonecompany_thread, "phonecompany",
  227.                    TASK, 0)))
  228.         thread_ready(t);
  229.     else
  230.         panic("thread_create/phonecompany");
  231.  
  232.     ipc_central_box = &TASK->answerbox;
  233. }
  234.