Subversion Repositories HelenOS

Rev

Rev 959 | 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.  
  109. /** Send a request using phone to answerbox
  110.  *
  111.  * @param phone Phone connected to answerbox
  112.  * @param request Request to be sent
  113.  */
  114. void ipc_call(phone_t *phone, call_t *request)
  115. {
  116.     answerbox_t *box = phone->callee;
  117.  
  118.     ASSERT(box);
  119.  
  120.     spinlock_lock(&box->lock);
  121.     list_append(&request->list, &box->calls);
  122.     spinlock_unlock(&box->lock);
  123.     waitq_wakeup(&box->wq, 0);
  124. }
  125.  
  126. /** Answer message back to phone
  127.  *
  128.  * @param box Answerbox that is answering the message
  129.  * @param request Modified request that is being sent back
  130.  */
  131. void ipc_answer(answerbox_t *box, call_t *request)
  132. {
  133.     answerbox_t *callerbox = request->callerbox;
  134.  
  135.     request->flags |= IPC_CALL_ANSWERED;
  136.  
  137.     spinlock_lock(&box->lock);
  138.     spinlock_lock(&callerbox->lock);
  139.  
  140.     list_remove(&request->list);
  141.     list_append(&request->list, &callerbox->answers);
  142.     waitq_wakeup(&callerbox->wq, 0);
  143.  
  144.     spinlock_unlock(&callerbox->lock);
  145.     spinlock_unlock(&box->lock);
  146. }
  147.  
  148. /** Wait for phone call
  149.  *
  150.  * @return Recived message address
  151.  * - to distinguish between call and answer, look at call->flags
  152.  */
  153. call_t * ipc_wait_for_call(answerbox_t *box, int flags)
  154. {
  155.     call_t *request;
  156.  
  157.     if ((flags & IPC_WAIT_NONBLOCKING)) {
  158.         if (waitq_sleep_timeout(&box->wq,SYNCH_NO_TIMEOUT,SYNCH_NON_BLOCKING) == ESYNCH_WOULD_BLOCK)
  159.             return 0;
  160.     } else {
  161.         waitq_sleep(&box->wq);
  162.     }
  163.  
  164.  
  165.     // TODO - might need condition variable+mutex if we want to support
  166.     // removing of requests from queue before dispatch
  167.     spinlock_lock(&box->lock);
  168.     /* Handle answers first */
  169.     if (!list_empty(&box->answers)) {
  170.         request = list_get_instance(box->answers.next, call_t, list);
  171.         list_remove(&request->list);
  172.     } else {
  173.         ASSERT (! list_empty(&box->calls));
  174.         request = list_get_instance(box->calls.next, call_t, list);
  175.         list_remove(&request->list);
  176.         /* Append request to dispatch queue */
  177.         list_append(&request->list, &box->dispatched_calls);
  178.     }
  179.     spinlock_unlock(&box->lock);
  180.  
  181.     return request;
  182. }
  183.  
  184. /** Initilize ipc subsystem */
  185. void ipc_init(void)
  186. {
  187.     ipc_call_slab = slab_cache_create("ipc_call",
  188.                       sizeof(call_t),
  189.                       0,
  190.                       NULL, NULL, 0);
  191. }
  192.  
  193. static void ipc_phonecompany_thread(void *data)
  194. {
  195.     call_t *call;
  196.  
  197.     printf("Phone company started.\n");
  198.     while (1) {
  199.         call = ipc_wait_for_call(&TASK->answerbox, 0);
  200.         printf("Received phone call - %P %P\n",
  201.                call->data[0], call->data[1]);
  202.         ipc_answer(&TASK->answerbox, call);
  203.         printf("Call answered.\n");
  204.     }
  205. }
  206.  
  207. void ipc_create_phonecompany(void)
  208. {
  209.     thread_t *t;
  210.    
  211.     if ((t = thread_create(ipc_phonecompany_thread, "phonecompany",
  212.                    TASK, 0)))
  213.         thread_ready(t);
  214.     else
  215.         panic("thread_create/phonecompany");
  216.  
  217.     ipc_central_box = &TASK->answerbox;
  218. }
  219.