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>
10 #include <lunaix/kpreempt.h>
12 #define MAX_POLLER_COUNT 16
15 current_rmiopoll(int pld)
17 iopoll_remove(current_thread, pld);
20 static struct iopoller*
21 iopoll_getpoller(struct iopoll* ctx, int pld)
23 if (pld < 0 || pld >= MAX_POLLER_COUNT) {
27 return ctx->pollers[pld];
31 __do_poll(struct poll_info* pinfo, int pld)
33 struct iopoller* poller = iopoll_getpoller(&__current->pollctx, pld);
41 if ((dev = resolve_device(poller->file_ref->inode->data))) {
44 // TODO handle generic file
46 N.B. In Linux, polling on any of the non-device mapped file cause
47 immediate return of poller, in other words, the I/O signal on file is
48 always active. Which make it no use on monitoring any file
49 modifications. However, polling for such modifications
50 must go through inotify_* API. Which is not that elegant as it breaks
51 the nice consistency that *poll(2) should have. Let see want can we
57 poll_setrevt(pinfo, _POLLERR);
61 if ((evt = poll_checkevt(pinfo, evt))) {
62 poll_setrevt(pinfo, evt);
69 if ((pinfo->flags & _POLLEE_RM_ON_ERR)) {
70 current_rmiopoll(pld);
75 if (!(pinfo->flags & _POLLEE_ALWAYS)) {
76 current_rmiopoll(pld);
83 __do_poll_round(struct poll_info* pinfos, int ninfo)
88 for (int i = 0; i < ninfo; i++) {
89 struct poll_info* pinfo = &pinfos[i];
92 if (__do_poll(pinfo, pld)) {
101 __do_poll_all(struct poll_info* pinfo)
103 for (int i = 0; i < MAX_POLLER_COUNT; i++) {
104 if (!__do_poll(pinfo, i)) {
115 #define fd2dev(fd) resolve_device((fd)->file->inode->data)
120 for (size_t i = 0; i < MAX_POLLER_COUNT; i++) {
121 if (!__current->pollctx.pollers[i]) {
130 __append_pollers(int* ds, int npoller)
134 for (int i = 0; i < npoller; i++) {
136 if ((err = vfs_getfd(*fd, &fd_s))) {
142 int pld = iopoll_install(current_thread, fd_s);
156 block_current_thread();
161 iopoll_init(struct iopoll* ctx)
163 ctx->pollers = vzalloc(sizeof(ptr_t) * MAX_POLLER_COUNT);
168 iopoll_free(struct proc_info* proc)
170 pid_t pid = proc->pid;
171 struct iopoll* ctx = &proc->pollctx;
172 for (int i = 0; i < MAX_POLLER_COUNT; i++) {
173 struct iopoller* poller = ctx->pollers[i];
175 vfs_pclose(poller->file_ref, pid);
176 llist_delete(&poller->evt_listener);
185 iopoll_wake_pollers(poll_evt_q* pollers_q)
187 struct iopoller *pos, *n;
188 llist_for_each(pos, n, pollers_q, evt_listener)
190 struct thread* thread = pos->thread;
191 assert(!proc_terminated(thread));
193 if (proc_hanged(thread)) {
194 resume_thread(thread);
200 iopoll_remove(struct thread* thread, int pld)
202 struct proc_info* proc = thread->process;
203 struct iopoll* ctx = &proc->pollctx;
204 struct iopoller* poller = ctx->pollers[pld];
209 // FIXME vfs locking model need to rethink in the presence of threads
210 vfs_pclose(poller->file_ref, proc->pid);
212 ctx->pollers[pld] = NULL;
219 iopoll_install(struct thread* thread, struct v_fd* fd)
221 int pld = __alloc_pld();
226 struct iopoller* iop = valloc(sizeof(struct iopoller));
227 *iop = (struct iopoller){
228 .file_ref = fd->file,
232 vfs_ref_file(fd->file);
234 struct proc_info* proc = thread->process;
235 proc->pollctx.pollers[pld] = iop;
236 proc->pollctx.n_poller++;
239 if ((dev = fd2dev(fd))) {
240 iopoll_listen_on(iop, &dev->pollers);
242 // TODO handle generic file
248 __DEFINE_LXSYSCALL2(int, pollctl, int, action, sc_va_list, _ap)
253 convert_valist(&va, _ap);
257 int* ds = va_arg(va, int*);
258 int nds = va_arg(va, int);
259 retcode = __append_pollers(ds, nds);
262 int pld = va_arg(va, int);
263 retcode = iopoll_remove(current_thread, pld);
266 struct poll_info* pinfos = va_arg(va, struct poll_info*);
267 int npinfos = va_arg(va, int);
268 int timeout = va_arg(va, int);
270 time_t t1 = clock_systime() + timeout;
271 while (!(retcode == __do_poll_round(pinfos, npinfos))) {
272 if (timeout >= 0 && t1 < clock_systime()) {
275 __wait_until_event();
278 case _SPOLL_WAIT_ANY: {
279 struct poll_info* pinfo = va_arg(va, struct poll_info*);
280 int timeout = va_arg(va, int);
282 time_t t1 = clock_systime() + timeout;
283 while (!(retcode == __do_poll_all(pinfo))) {
284 if (timeout >= 0 && t1 < clock_systime()) {
287 __wait_until_event();
295 return DO_STATUS(retcode);