| 1 | #include <sch/sched.h> |
| 2 | #include <thread/io_wait.h> |
| 3 | #include <thread/thread.h> |
| 4 | |
| 5 | static atomic_size_t io_wait_magic = ATOMIC_VAR_INIT(0); |
| 6 | |
| 7 | void io_wait_begin(struct io_wait_token *out, void *io_object) { |
| 8 | struct thread *t = thread_get_current(); |
| 9 | |
| 10 | *out = (struct io_wait_token){.wait_object = io_object, |
| 11 | .active = true, |
| 12 | .magic = atomic_fetch_add(&io_wait_magic, 1), |
| 13 | .owner = t}; |
| 14 | list_add_tail(new: &out->list, head: &t->io_wait_tokens); |
| 15 | |
| 16 | thread_prepare_to_block(t, r: THREAD_BLOCK_REASON_IO, |
| 17 | wait_type: THREAD_WAIT_UNINTERRUPTIBLE, expect_wake_src: io_object); |
| 18 | } |
| 19 | |
| 20 | void io_wait_end(struct io_wait_token *t, enum io_wait_end_action act) { |
| 21 | struct thread *c = thread_get_current(); |
| 22 | bool found = false; |
| 23 | |
| 24 | /* double check */ |
| 25 | struct io_wait_token *iter; |
| 26 | list_for_each_entry(iter, &c->io_wait_tokens, list) { |
| 27 | kassert(iter->active); |
| 28 | kassert(iter->owner == c); |
| 29 | if (iter == t) { |
| 30 | found = true; |
| 31 | break; |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | kassert(found); |
| 36 | |
| 37 | list_del(entry: &t->list); |
| 38 | |
| 39 | if (list_empty(head: &c->io_wait_tokens)) { |
| 40 | thread_unboost_self(); |
| 41 | |
| 42 | if (act == IO_WAIT_END_YIELD) |
| 43 | scheduler_yield(); |
| 44 | } |
| 45 | |
| 46 | t->active = false; |
| 47 | } |
| 48 | |