krxiod.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* krxiod.c: Rx I/O daemon
  2. *
  3. * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/sched.h>
  12. #include <linux/completion.h>
  13. #include <linux/spinlock.h>
  14. #include <linux/init.h>
  15. #include <linux/freezer.h>
  16. #include <rxrpc/krxiod.h>
  17. #include <rxrpc/transport.h>
  18. #include <rxrpc/peer.h>
  19. #include <rxrpc/call.h>
  20. #include "internal.h"
  21. static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxiod_sleepq);
  22. static DECLARE_COMPLETION(rxrpc_krxiod_dead);
  23. static atomic_t rxrpc_krxiod_qcount = ATOMIC_INIT(0);
  24. static LIST_HEAD(rxrpc_krxiod_transportq);
  25. static DEFINE_SPINLOCK(rxrpc_krxiod_transportq_lock);
  26. static LIST_HEAD(rxrpc_krxiod_callq);
  27. static DEFINE_SPINLOCK(rxrpc_krxiod_callq_lock);
  28. static volatile int rxrpc_krxiod_die;
  29. /*****************************************************************************/
  30. /*
  31. * Rx I/O daemon
  32. */
  33. static int rxrpc_krxiod(void *arg)
  34. {
  35. DECLARE_WAITQUEUE(krxiod,current);
  36. printk("Started krxiod %d\n",current->pid);
  37. daemonize("krxiod");
  38. /* loop around waiting for work to do */
  39. do {
  40. /* wait for work or to be told to exit */
  41. _debug("### Begin Wait");
  42. if (!atomic_read(&rxrpc_krxiod_qcount)) {
  43. set_current_state(TASK_INTERRUPTIBLE);
  44. add_wait_queue(&rxrpc_krxiod_sleepq, &krxiod);
  45. for (;;) {
  46. set_current_state(TASK_INTERRUPTIBLE);
  47. if (atomic_read(&rxrpc_krxiod_qcount) ||
  48. rxrpc_krxiod_die ||
  49. signal_pending(current))
  50. break;
  51. schedule();
  52. }
  53. remove_wait_queue(&rxrpc_krxiod_sleepq, &krxiod);
  54. set_current_state(TASK_RUNNING);
  55. }
  56. _debug("### End Wait");
  57. /* do work if been given some to do */
  58. _debug("### Begin Work");
  59. /* see if there's a transport in need of attention */
  60. if (!list_empty(&rxrpc_krxiod_transportq)) {
  61. struct rxrpc_transport *trans = NULL;
  62. spin_lock_irq(&rxrpc_krxiod_transportq_lock);
  63. if (!list_empty(&rxrpc_krxiod_transportq)) {
  64. trans = list_entry(
  65. rxrpc_krxiod_transportq.next,
  66. struct rxrpc_transport,
  67. krxiodq_link);
  68. list_del_init(&trans->krxiodq_link);
  69. atomic_dec(&rxrpc_krxiod_qcount);
  70. /* make sure it hasn't gone away and doesn't go
  71. * away */
  72. if (atomic_read(&trans->usage)>0)
  73. rxrpc_get_transport(trans);
  74. else
  75. trans = NULL;
  76. }
  77. spin_unlock_irq(&rxrpc_krxiod_transportq_lock);
  78. if (trans) {
  79. rxrpc_trans_receive_packet(trans);
  80. rxrpc_put_transport(trans);
  81. }
  82. }
  83. /* see if there's a call in need of attention */
  84. if (!list_empty(&rxrpc_krxiod_callq)) {
  85. struct rxrpc_call *call = NULL;
  86. spin_lock_irq(&rxrpc_krxiod_callq_lock);
  87. if (!list_empty(&rxrpc_krxiod_callq)) {
  88. call = list_entry(rxrpc_krxiod_callq.next,
  89. struct rxrpc_call,
  90. rcv_krxiodq_lk);
  91. list_del_init(&call->rcv_krxiodq_lk);
  92. atomic_dec(&rxrpc_krxiod_qcount);
  93. /* make sure it hasn't gone away and doesn't go
  94. * away */
  95. if (atomic_read(&call->usage) > 0) {
  96. _debug("@@@ KRXIOD"
  97. " Begin Attend Call %p", call);
  98. rxrpc_get_call(call);
  99. }
  100. else {
  101. call = NULL;
  102. }
  103. }
  104. spin_unlock_irq(&rxrpc_krxiod_callq_lock);
  105. if (call) {
  106. rxrpc_call_do_stuff(call);
  107. rxrpc_put_call(call);
  108. _debug("@@@ KRXIOD End Attend Call %p", call);
  109. }
  110. }
  111. _debug("### End Work");
  112. try_to_freeze();
  113. /* discard pending signals */
  114. rxrpc_discard_my_signals();
  115. } while (!rxrpc_krxiod_die);
  116. /* and that's all */
  117. complete_and_exit(&rxrpc_krxiod_dead, 0);
  118. } /* end rxrpc_krxiod() */
  119. /*****************************************************************************/
  120. /*
  121. * start up a krxiod daemon
  122. */
  123. int __init rxrpc_krxiod_init(void)
  124. {
  125. return kernel_thread(rxrpc_krxiod, NULL, 0);
  126. } /* end rxrpc_krxiod_init() */
  127. /*****************************************************************************/
  128. /*
  129. * kill the krxiod daemon and wait for it to complete
  130. */
  131. void rxrpc_krxiod_kill(void)
  132. {
  133. rxrpc_krxiod_die = 1;
  134. wake_up_all(&rxrpc_krxiod_sleepq);
  135. wait_for_completion(&rxrpc_krxiod_dead);
  136. } /* end rxrpc_krxiod_kill() */
  137. /*****************************************************************************/
  138. /*
  139. * queue a transport for attention by krxiod
  140. */
  141. void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans)
  142. {
  143. unsigned long flags;
  144. _enter("");
  145. if (list_empty(&trans->krxiodq_link)) {
  146. spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags);
  147. if (list_empty(&trans->krxiodq_link)) {
  148. if (atomic_read(&trans->usage) > 0) {
  149. list_add_tail(&trans->krxiodq_link,
  150. &rxrpc_krxiod_transportq);
  151. atomic_inc(&rxrpc_krxiod_qcount);
  152. }
  153. }
  154. spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags);
  155. wake_up_all(&rxrpc_krxiod_sleepq);
  156. }
  157. _leave("");
  158. } /* end rxrpc_krxiod_queue_transport() */
  159. /*****************************************************************************/
  160. /*
  161. * dequeue a transport from krxiod's attention queue
  162. */
  163. void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans)
  164. {
  165. unsigned long flags;
  166. _enter("");
  167. spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags);
  168. if (!list_empty(&trans->krxiodq_link)) {
  169. list_del_init(&trans->krxiodq_link);
  170. atomic_dec(&rxrpc_krxiod_qcount);
  171. }
  172. spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags);
  173. _leave("");
  174. } /* end rxrpc_krxiod_dequeue_transport() */
  175. /*****************************************************************************/
  176. /*
  177. * queue a call for attention by krxiod
  178. */
  179. void rxrpc_krxiod_queue_call(struct rxrpc_call *call)
  180. {
  181. unsigned long flags;
  182. if (list_empty(&call->rcv_krxiodq_lk)) {
  183. spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags);
  184. if (atomic_read(&call->usage) > 0) {
  185. list_add_tail(&call->rcv_krxiodq_lk,
  186. &rxrpc_krxiod_callq);
  187. atomic_inc(&rxrpc_krxiod_qcount);
  188. }
  189. spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags);
  190. }
  191. wake_up_all(&rxrpc_krxiod_sleepq);
  192. } /* end rxrpc_krxiod_queue_call() */
  193. /*****************************************************************************/
  194. /*
  195. * dequeue a call from krxiod's attention queue
  196. */
  197. void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call)
  198. {
  199. unsigned long flags;
  200. spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags);
  201. if (!list_empty(&call->rcv_krxiodq_lk)) {
  202. list_del_init(&call->rcv_krxiodq_lk);
  203. atomic_dec(&rxrpc_krxiod_qcount);
  204. }
  205. spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags);
  206. } /* end rxrpc_krxiod_dequeue_call() */