summaryrefslogtreecommitdiff
path: root/src/cry_stubs.c
blob: 5246fa115d372984fb1bab5a0d8fb6240a1e00f8 (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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <caml/alloc.h>
#include <caml/bigarray.h>
#include <caml/fail.h>
#include <caml/memory.h>
#include <caml/signals.h>
#include <caml/threads.h>
#include <caml/unixsupport.h>

#include <errno.h>

/* On native Windows platforms, many macros are not defined.  */
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__

#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif

#endif

#ifdef WIN32
#define Fd_val(fd) win_CRT_fd_of_filedescr(fd)
#define Val_fd(fd) caml_failwith("Val_fd")
#else
#define Fd_val(fd) Int_val(fd)
#define Val_fd(fd) Val_int(fd)
#endif

#ifndef WIN32
#include <poll.h>

CAMLprim value caml_cry_poll(value _read, value _write, value _err,
                             value _timeout) {
  CAMLparam3(_read, _write, _err);
  CAMLlocal4(_pread, _pwrite, _perr, _ret);

  struct pollfd *fds;
  nfds_t nfds = 0;
  nfds_t nread = 0;
  nfds_t nwrite = 0;
  nfds_t nerr = 0;
  int timeout;
  size_t last = 0;
  int n, ret;

  if (Double_val(_timeout) == -1)
    timeout = -1;
  else
    timeout = Double_val(_timeout) * 1000;

  nfds += Wosize_val(_read);
  nfds += Wosize_val(_write);
  nfds += Wosize_val(_err);

  fds = calloc(nfds, sizeof(struct pollfd));
  if (fds == NULL)
    caml_raise_out_of_memory();

  for (n = 0; n < Wosize_val(_read); n++) {
    fds[last + n].fd = Fd_val(Field(_read, n));
    fds[last + n].events = POLLIN;
  }
  last += Wosize_val(_read);

  for (n = 0; n < Wosize_val(_write); n++) {
    fds[last + n].fd = Fd_val(Field(_write, n));
    fds[last + n].events = POLLOUT;
  }
  last += Wosize_val(_write);

  for (n = 0; n < Wosize_val(_err); n++) {
    fds[last + n].fd = Fd_val(Field(_err, n));
    fds[last + n].events = POLLERR;
  }

  caml_release_runtime_system();
  ret = poll(fds, nfds, timeout);
  caml_acquire_runtime_system();

  if (ret == -1) {
    free(fds);
    uerror("poll", Nothing);
  }

  for (n = 0; n < nfds; n++) {
    if (fds[n].revents & POLLIN)
      nread++;
    if (fds[n].revents & POLLOUT)
      nwrite++;
    if (fds[n].revents & POLLERR)
      nerr++;
  }

  _pread = caml_alloc_tuple(nread);
  nread = 0;

  _pwrite = caml_alloc_tuple(nwrite);
  nwrite = 0;

  _perr = caml_alloc_tuple(nerr);
  nerr = 0;

  for (n = 0; n < nfds; n++) {
    if (fds[n].revents & POLLIN) {
      Store_field(_pread, nread, Val_fd(fds[n].fd));
      nread++;
    }
    if (fds[n].revents & POLLOUT) {
      Store_field(_pwrite, nwrite, Val_fd(fds[n].fd));
      nwrite++;
    }
    if (fds[n].revents & POLLERR) {
      Store_field(_pread, nerr, Val_fd(fds[n].fd));
      nerr++;
    }
  }

  free(fds);

  _ret = caml_alloc_tuple(3);
  Store_field(_ret, 0, _pread);
  Store_field(_ret, 1, _pwrite);
  Store_field(_ret, 2, _perr);

  CAMLreturn(_ret);
}
#else
CAMLprim value caml_cry_poll(value _read, value _write, value _err,
                             value _timeout) {
  caml_failwith("caml_poll");
}
#endif