eventcount.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
  4. * Copyright (c) 1993,1994 The University of Utah and
  5. * the Computer Systems Laboratory (CSL).
  6. * All rights reserved.
  7. *
  8. * Permission to use, copy, modify and distribute this software and its
  9. * documentation is hereby granted, provided that both the copyright
  10. * notice and this permission notice appear in all copies of the
  11. * software, derivative works or modified versions, and any portions
  12. * thereof, and that both notices appear in supporting documentation.
  13. *
  14. * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
  15. * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
  16. * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
  17. * THIS SOFTWARE.
  18. *
  19. * Carnegie Mellon requests users of this software to return to
  20. *
  21. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  22. * School of Computer Science
  23. * Carnegie Mellon University
  24. * Pittsburgh PA 15213-3890
  25. *
  26. * any improvements or extensions that they make and grant Carnegie Mellon
  27. * the rights to redistribute these changes.
  28. */
  29. /*
  30. * File: eventcount.c
  31. * Author: Alessandro Forin
  32. * Date: 10/91
  33. *
  34. * Eventcounters, for user-level drivers synchronization
  35. *
  36. */
  37. #include <kern/printf.h>
  38. #include <string.h>
  39. #include <mach/machine.h>
  40. #include <kern/ast.h>
  41. #include <kern/debug.h>
  42. #include "cpu_number.h"
  43. #include <kern/lock.h>
  44. #include <kern/processor.h>
  45. #include <kern/queue.h>
  46. #include <kern/sched.h>
  47. #include <kern/sched_prim.h>
  48. #include <kern/thread.h>
  49. #include <machine/machspl.h> /* For def'n of splsched() */
  50. #include <kern/eventcount.h>
  51. #define MAX_EVCS 10 /* xxx for now */
  52. evc_t all_eventcounters[MAX_EVCS];
  53. /*
  54. * Initialization
  55. */
  56. void
  57. evc_init(evc_t ev)
  58. {
  59. int i;
  60. memset(ev, 0, sizeof(*ev));
  61. /* keep track of who is who */
  62. for (i = 0; i < MAX_EVCS; i++)
  63. if (all_eventcounters[i] == 0) break;
  64. if (i == MAX_EVCS) {
  65. printf("Too many eventcounters\n");
  66. return;
  67. }
  68. all_eventcounters[i] = ev;
  69. ev->ev_id = i;
  70. ev->sanity = ev;
  71. ev->waiting_thread = THREAD_NULL;
  72. simple_lock_init(&ev->lock);
  73. }
  74. /*
  75. * Finalization
  76. */
  77. void
  78. evc_destroy(evc_t ev)
  79. {
  80. evc_signal(ev);
  81. ev->sanity = 0;
  82. if (all_eventcounters[ev->ev_id] == ev)
  83. all_eventcounters[ev->ev_id] = 0;
  84. ev->ev_id = -1;
  85. }
  86. /*
  87. * Thread termination.
  88. * HORRIBLE. This stuff needs to be fixed.
  89. */
  90. void evc_notify_abort(const thread_t thread)
  91. {
  92. int i;
  93. evc_t ev;
  94. int s = splsched();
  95. for (i = 0; i < MAX_EVCS; i++) {
  96. ev = all_eventcounters[i];
  97. if (ev) {
  98. simple_lock(&ev->lock);
  99. if (ev->waiting_thread == thread)
  100. {
  101. ev->waiting_thread = 0;
  102. /* Removal of a waiting thread has to bump the count by one */
  103. ev->count++;
  104. }
  105. simple_unlock(&ev->lock);
  106. }
  107. }
  108. splx(s);
  109. }
  110. /*
  111. * Just so that we return success, and give
  112. * up the stack while blocked
  113. */
  114. static void __attribute__((noreturn))
  115. evc_continue(void)
  116. {
  117. thread_syscall_return(KERN_SUCCESS);
  118. /* NOTREACHED */
  119. }
  120. /*
  121. * User-trappable
  122. */
  123. kern_return_t evc_wait(natural_t ev_id)
  124. {
  125. spl_t s;
  126. kern_return_t ret;
  127. evc_t ev;
  128. if ((ev_id >= MAX_EVCS) ||
  129. ((ev = all_eventcounters[ev_id]) == 0) ||
  130. (ev->ev_id != ev_id) || (ev->sanity != ev))
  131. return KERN_INVALID_ARGUMENT;
  132. s = splsched();
  133. simple_lock(&ev->lock);
  134. /*
  135. * The values assumed by the "count" field are
  136. * as follows:
  137. * 0 At initialization time, and with no
  138. * waiting thread means no events pending;
  139. * with waiting thread means the event
  140. * was signalled and the thread not yet resumed
  141. * -1 no events, there must be a waiting thread
  142. * N>0 no waiting thread means N pending,
  143. * with waiting thread N-1 pending.
  144. *
  145. */
  146. if (ev->count > 0) {
  147. ev->count--;
  148. ret = KERN_SUCCESS;
  149. } else {
  150. if (ev->waiting_thread == THREAD_NULL) {
  151. ev->count--;
  152. ev->waiting_thread = current_thread();
  153. assert_wait((event_t) 0, TRUE); /* ifnot race */
  154. simple_unlock(&ev->lock);
  155. thread_block(evc_continue);
  156. return KERN_SUCCESS;
  157. }
  158. ret = KERN_NO_SPACE; /* XX */
  159. }
  160. simple_unlock(&ev->lock);
  161. splx(s);
  162. return ret;
  163. }
  164. /*
  165. * User-trappable
  166. */
  167. kern_return_t evc_wait_clear(natural_t ev_id)
  168. {
  169. spl_t s;
  170. evc_t ev;
  171. if ((ev_id >= MAX_EVCS) ||
  172. ((ev = all_eventcounters[ev_id]) == 0) ||
  173. (ev->ev_id != ev_id) || (ev->sanity != ev))
  174. return KERN_INVALID_ARGUMENT;
  175. s = splsched();
  176. simple_lock(&ev->lock);
  177. /*
  178. * The values assumed by the "count" field are
  179. * as follows:
  180. * 0 At initialization time, and with no
  181. * waiting thread means no events pending;
  182. * with waiting thread means the event
  183. * was signalled and the thread not yet resumed
  184. * -1 no events, there must be a waiting thread
  185. * N>0 no waiting thread means N pending,
  186. * with waiting thread N-1 pending.
  187. *
  188. */
  189. /*
  190. * Note that we always clear count before blocking.
  191. */
  192. if (ev->waiting_thread == THREAD_NULL) {
  193. ev->count = -1;
  194. ev->waiting_thread = current_thread();
  195. assert_wait((event_t) 0, TRUE); /* ifnot race */
  196. simple_unlock(&ev->lock);
  197. thread_block(evc_continue);
  198. /* NOTREACHED */
  199. }
  200. simple_unlock(&ev->lock);
  201. splx(s);
  202. return KERN_NO_SPACE; /* XX */
  203. }
  204. /*
  205. * Called exclusively from interrupt context
  206. */
  207. void
  208. evc_signal(evc_t ev)
  209. {
  210. volatile thread_t thread;
  211. int state;
  212. spl_t s;
  213. if (ev->sanity != ev)
  214. return;
  215. s = splsched();
  216. simple_lock(&ev->lock);
  217. ev->count++;
  218. if (thread = ev->waiting_thread, thread != THREAD_NULL)
  219. {
  220. ev->waiting_thread = 0;
  221. #if (NCPUS > 1)
  222. retry:
  223. while((thread->state & TH_RUN) || thread->lock.lock_data)
  224. ;
  225. #endif
  226. thread_lock(thread);
  227. /* make thread runnable on this processor */
  228. /* taken from clear_wait */
  229. switch ((state = thread->state) & TH_SCHED_STATE)
  230. {
  231. case TH_WAIT | TH_SUSP | TH_UNINT:
  232. case TH_WAIT | TH_UNINT:
  233. case TH_WAIT:
  234. /*
  235. * Sleeping and not suspendable - put
  236. * on run queue.
  237. */
  238. thread->state = (state &~ TH_WAIT) | TH_RUN;
  239. thread_unlock(thread);
  240. #if NCPUS > 1
  241. thread_setrun(thread, TRUE);
  242. #else
  243. simpler_thread_setrun(thread, TRUE);
  244. #endif
  245. break;
  246. case TH_RUN | TH_WAIT:
  247. #if (NCPUS > 1)
  248. /*
  249. * Legal on MP: between assert_wait()
  250. * and thread_block(), in evc_wait() above.
  251. *
  252. * Mmm. Maybe don't need now that the while(..) check is
  253. * done before the thread lock is grabbed.....
  254. */
  255. thread_unlock(thread);
  256. goto retry;
  257. #else
  258. /*FALLTHROUGH*/
  259. #endif
  260. case TH_WAIT | TH_SUSP:
  261. case TH_RUN | TH_WAIT | TH_SUSP:
  262. case TH_RUN | TH_WAIT | TH_UNINT:
  263. case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
  264. /*
  265. * Either already running, or suspended.
  266. * Just clear the wait.
  267. */
  268. thread->state = state &~ TH_WAIT;
  269. thread_unlock(thread);
  270. break;
  271. default:
  272. /*
  273. * Not waiting.
  274. */
  275. panic("evc_signal.3");
  276. thread_unlock(thread);
  277. break;
  278. }
  279. }
  280. simple_unlock(&ev->lock);
  281. splx(s);
  282. }
  283. #if NCPUS <= 1
  284. /*
  285. * The scheduler is too messy for my old little brain
  286. */
  287. void
  288. simpler_thread_setrun(
  289. thread_t th,
  290. boolean_t may_preempt)
  291. {
  292. struct run_queue *rq;
  293. int whichq;
  294. /*
  295. * XXX should replace queue with a boolean in this case.
  296. */
  297. if (default_pset.idle_count > 0) {
  298. processor_t processor;
  299. processor = (processor_t) queue_first(&default_pset.idle_queue);
  300. queue_remove(&default_pset.idle_queue, processor,
  301. processor_t, processor_queue);
  302. default_pset.idle_count--;
  303. processor->next_thread = th;
  304. processor->state = PROCESSOR_DISPATCHING;
  305. return;
  306. }
  307. rq = &(master_processor->runq);
  308. ast_on(cpu_number(), AST_BLOCK);
  309. whichq = (th)->sched_pri;
  310. simple_lock(&(rq)->lock); /* lock the run queue */
  311. enqueue_head(&(rq)->runq[whichq], &((th)->links));
  312. if (whichq < (rq)->low || (rq)->count == 0)
  313. (rq)->low = whichq; /* minimize */
  314. (rq)->count++;
  315. #ifdef MIGRATING_THREADS
  316. (th)->shuttle.runq = (rq);
  317. #else
  318. (th)->runq = (rq);
  319. #endif
  320. simple_unlock(&(rq)->lock);
  321. /*
  322. * Turn off first_quantum to allow context switch.
  323. */
  324. current_processor()->first_quantum = FALSE;
  325. }
  326. #endif /* NCPUS > 1 */