1 #include <lunaix/clock.h>
2 #include <lunaix/device.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/process.h>
6 #include <lunaix/sched.h>
7 #include <lunaix/spike.h>
8 #include <lunaix/syscall.h>
9 #include <lunaix/syscall_utils.h>
11 #define MAX_POLLER_COUNT 16
14 current_rmiopoll(int pld)
16 iopoll_remove(current_thread, pld);
19 static struct iopoller*
20 iopoll_getpoller(struct iopoll* ctx, int pld)
22 if (pld < 0 || pld >= MAX_POLLER_COUNT) {
26 return ctx->pollers[pld];
30 __do_poll(struct poll_info* pinfo, int pld)
32 struct iopoller* poller = iopoll_getpoller(&__current->pollctx, pld);
40 if ((dev = resolve_device(poller->file_ref->inode->data))) {
43 // TODO handle generic file
45 N.B. In Linux, polling on any of the non-device mapped file cause
46 immediate return of poller, in other words, the I/O signal on file is
47 always active. Which make it no use on monitoring any file
48 modifications. However, polling for such modifications
49 must go through inotify_* API. Which is not that elegant as it breaks
50 the nice consistency that *poll(2) should have. Let see want can we
56 poll_setrevt(pinfo, _POLLERR);
60 if ((evt = poll_checkevt(pinfo, evt))) {
61 poll_setrevt(pinfo, evt);
68 if ((pinfo->flags & _POLLEE_RM_ON_ERR)) {
69 current_rmiopoll(pld);
74 if (!(pinfo->flags & _POLLEE_ALWAYS)) {
75 current_rmiopoll(pld);
82 __do_poll_round(struct poll_info* pinfos, int ninfo)
87 for (int i = 0; i < ninfo; i++) {
88 struct poll_info* pinfo = &pinfos[i];
91 if (__do_poll(pinfo, pld)) {
100 __do_poll_all(struct poll_info* pinfo)
102 for (int i = 0; i < MAX_POLLER_COUNT; i++) {
103 if (!__do_poll(pinfo, i)) {
114 #define fd2dev(fd) resolve_device((fd)->file->inode->data)
119 for (size_t i = 0; i < MAX_POLLER_COUNT; i++) {
120 if (!__current->pollctx.pollers[i]) {
129 __append_pollers(int* ds, int npoller)
133 for (int i = 0; i < npoller; i++) {
135 if ((err = vfs_getfd(*fd, &fd_s))) {
141 int pld = iopoll_install(current_thread, fd_s);
155 block_current_thread();
160 iopoll_init(struct iopoll* ctx)
162 ctx->pollers = vzalloc(sizeof(ptr_t) * MAX_POLLER_COUNT);
167 iopoll_free(struct proc_info* proc)
169 pid_t pid = proc->pid;
170 struct iopoll* ctx = &proc->pollctx;
171 for (int i = 0; i < MAX_POLLER_COUNT; i++) {
172 struct iopoller* poller = ctx->pollers[i];
174 vfs_pclose(poller->file_ref, pid);
175 llist_delete(&poller->evt_listener);
184 iopoll_wake_pollers(poll_evt_q* pollers_q)
186 struct iopoller *pos, *n;
187 llist_for_each(pos, n, pollers_q, evt_listener)
189 struct thread* thread = pos->thread;
190 assert(!proc_terminated(thread));
192 if (proc_hanged(thread)) {
193 resume_thread(thread);
199 iopoll_remove(struct thread* thread, int pld)
201 struct proc_info* proc = thread->process;
202 struct iopoll* ctx = &proc->pollctx;
203 struct iopoller* poller = ctx->pollers[pld];
208 // FIXME vfs locking model need to rethink in the presence of threads
209 vfs_pclose(poller->file_ref, proc->pid);
211 ctx->pollers[pld] = NULL;
218 iopoll_install(struct thread* thread, struct v_fd* fd)
220 int pld = __alloc_pld();
225 struct iopoller* iop = valloc(sizeof(struct iopoller));
226 *iop = (struct iopoller){
227 .file_ref = fd->file,
231 vfs_ref_file(fd->file);
233 struct proc_info* proc = thread->process;
234 proc->pollctx.pollers[pld] = iop;
235 proc->pollctx.n_poller++;
238 if ((dev = fd2dev(fd))) {
239 iopoll_listen_on(iop, &dev->pollers);
241 // TODO handle generic file
247 __DEFINE_LXSYSCALL2(int, pollctl, int, action, sc_va_list, _ap)
252 convert_valist(&va, _ap);
256 int* ds = va_arg(va, int*);
257 int nds = va_arg(va, int);
258 retcode = __append_pollers(ds, nds);
261 int pld = va_arg(va, int);
262 retcode = iopoll_remove(current_thread, pld);
265 struct poll_info* pinfos = va_arg(va, struct poll_info*);
266 int npinfos = va_arg(va, int);
267 int timeout = va_arg(va, int);
269 time_t t1 = clock_systime() + timeout;
270 while (!(retcode == __do_poll_round(pinfos, npinfos))) {
271 if (timeout >= 0 && t1 < clock_systime()) {
274 __wait_until_event();
277 case _SPOLL_WAIT_ANY: {
278 struct poll_info* pinfo = va_arg(va, struct poll_info*);
279 int timeout = va_arg(va, int);
281 time_t t1 = clock_systime() + timeout;
282 while (!(retcode == __do_poll_all(pinfo))) {
283 if (timeout >= 0 && t1 < clock_systime()) {
286 __wait_until_event();
294 return DO_STATUS(retcode);