Ajla 0.1.0
[ajla.git] / iomux.inc
blobe7a4904134993dab18061546c023176d5a783fd1
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 rwlock_decl(iomux_rwlock);
21 static struct iomux_wait **iowait_directory;
22 static size_t iowait_directory_size;
24 static bool iomux_poll = false;
26 void iomux_enable_poll(void)
28         bool was_poll = iomux_poll;
29         if (unlikely(!was_poll)) {
30                 iomux_poll = true;
31                 os_notify();
32         }
35 void iomux_never(mutex_t **mutex_to_lock, struct list *list_entry)
37         *mutex_to_lock = address_get_mutex(NULL, DEPTH_THUNK);
38         list_init(list_entry);
41 static struct iomux_wait *iomux_get_iowait(handle_t handle)
43         struct iomux_wait *result;
45         rwlock_lock_read(&iomux_rwlock);
46         if (likely((size_t)handle < iowait_directory_size) && likely((result = iowait_directory[handle]) != NULL)) {
47                 rwlock_unlock_read(&iomux_rwlock);
48                 return result;
49         }
50         rwlock_unlock_read(&iomux_rwlock);
52         rwlock_lock_write(&iomux_rwlock);
53         while ((size_t)handle >= iowait_directory_size) {
54                 array_add(struct iomux_wait *, &iowait_directory, &iowait_directory_size, NULL);
55         }
57         if (!(result = iowait_directory[handle])) {
58                 result = iowait_directory[handle] = mem_alloc(struct iomux_wait *, sizeof(struct iomux_wait));
59                 iomux_wait_init(result, handle);
60         }
62         rwlock_unlock_write(&iomux_rwlock);
63         return result;
66 static uint32_t iomux_get_time(uint32_t us)
68         if (unlikely(iomux_poll))
69                 us = minimum(us, POLL_US);
71 #ifndef TIMER_THREAD
72         {
73                 uint32_t tm = timer_wait_now();
74                 us = minimum(us, tm);
75         }
76 #endif
78         return us;
82 #ifndef THREAD_NONE
84 static thread_t iomux_thread;
86 #ifndef TIMER_THREAD
87 #define do_timer_check_all      timer_check_all()
88 #else
89 #define do_timer_check_all      do { } while (0)
90 #endif
93  * select doesn't work well with signals, the standard says that it's
94  * implementation-defined whether SA_RESTART restarts select or not.
95  *
96  * If SA_RESTART signal restarts select with the original timeval, it causes
97  * livelock.
98  *
99  * So, we'd better disable signals for the iomux thread and let the system
100  * deliver them to another thread.
101  */
102 #if defined(IOMUX_SELECT)
103 #define iomux_block_signals     true
104 #else
105 #define iomux_block_signals     false
106 #endif
108 thread_function_decl(iomux_poll_thread,
109         sig_state_t set;
110         if (iomux_block_signals)
111                 os_block_signals(&set);
112         thread_set_id(-1);
113         while (likely(!os_drain_notify_pipe())) {
114                 do_timer_check_all;
115                 os_proc_check_all();
116                 os_signal_check_all();
117                 iomux_check_all(IOMUX_INDEFINITE_WAIT);
118         }
119         if (iomux_block_signals)
120                 os_unblock_signals(&set);
123 #endif