summaryrefslogtreecommitdiff
path: root/kernel/poll.c
blob: 211faf73ef082b94398370cb22e921a85fe7f235 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <fs/vfs.h>
#include <halts.h>
#include <poll.h>
#include <sched/scheduler.h>

int poll(struct pollfd *fds, size_t nfds, int timeout) {
  (void)timeout;
  int rc = 0;
  int read_locks[nfds];
  int write_locks[nfds];
  int disconnect_locks[nfds];
  for (size_t i = 0; i < nfds; i++) {
    if (fds[i].fd < 0)
      continue;
    vfs_fd_t *f = get_vfs_fd(fds[i].fd);
    if (fds[i].events & POLLIN)
      read_locks[i] = create_read_fdhalt(f);
    if (fds[i].events & POLLOUT)
      write_locks[i] = create_write_fdhalt(f);
    if (fds[i].events & POLLHUP)
      disconnect_locks[i] = create_disconnect_fdhalt(f);
  }

  switch_task();

  for (size_t i = 0; i < nfds; i++) {
    if (fds[i].fd < 0)
      continue;
    if (fds[i].events & POLLIN)
      unset_read_fdhalt(read_locks[i]);
    if (fds[i].events & POLLOUT)
      unset_write_fdhalt(write_locks[i]);
    if (fds[i].events & POLLHUP)
      unset_disconnect_fdhalt(disconnect_locks[i]);
  }
  for (size_t i = 0; i < nfds; i++) {
    if (0 > fds[i].fd) {
      fds[i].revents = 0;
      continue;
    }
    vfs_fd_t *f = get_vfs_fd(fds[i].fd);
    if (!f) {
      if (fds[i].events & POLLHUP)
        fds[i].revents |= POLLHUP;
    } else {
      if (f->inode->has_data && fds[i].events & POLLIN)
        fds[i].revents |= POLLIN;
      if (f->inode->can_write && fds[i].events & POLLOUT)
        fds[i].revents |= POLLOUT;
      if (!(f->inode->is_open) && fds[i].events & POLLHUP)
        fds[i].revents |= POLLHUP;
      if (fds[i].revents)
        rc++;
    }
  }
  return rc;
}