1 /*
2 * $Id: uevent.c,v 1.1 2005-09-18 22:05:39 dhmunro Exp $
3 * UNIX input event handling
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 #ifndef _HPUX_SOURCE
12 /* HPUX turns off poll.h without this (_INCLUDE_AES_SOURCE) */
13 #define _HPUX_SOURCE 1
14 #endif
15 #ifndef _XOPEN_SOURCE_EXTENDED
16 /* Digital UNIX needs _XOPEN_SOURCE_EXTENDED for poll.h to work */
17 #define _XOPEN_SOURCE_EXTENDED 1
18 #endif
19
20 #include "config.h"
21 #include "play.h"
22 #include "playu.h"
23 #include "pstdlib.h"
24
25 #ifdef TEST_POLL
26 #define p_realloc (void *)realloc
27 #define p_malloc (void *)malloc
u_fdwatch(int fd,int on)28 void u_fdwatch(int fd, int on) {}
29 #endif
30
31 /* errno determines if a signal caused premature return from poll */
32 #include <errno.h>
33
34 #ifndef USE_SELECT
35 # ifndef USE_SYS_POLL_H
36 # include <poll.h>
37 # else
38 # include <sys/poll.h>
39 # endif
40 # define u__poll poll
41 #else
42 # include "upoll.h"
43 # include "upoll.c"
44 #endif
45
46 typedef struct u_handler u_handler;
47 struct u_handler {
48 void (*callback)(void *);
49 void *context;
50 };
51
52 static u_handler *poll_handler = 0;
53 static struct pollfd *poll_fds = 0;
54 static unsigned long poll_nfds = 0;
55 static unsigned long poll_maxfd = 0;
56
57 typedef struct u_prehandler u_prehandler;
58 struct u_prehandler {
59 int (*conditional)(void *);
60 void *context;
61 };
62
63 static u_prehandler *prepoll = 0;
64 static int prepoll_i = 0;
65 static int prepoll_n = 0;
66 static int prepoll_mx = 0;
67
68 void
u_event_src(int fd,void (* callback)(void *),void * context)69 u_event_src(int fd, void (*callback)(void *), void *context)
70 {
71 if (callback) {
72 if (poll_nfds>=poll_maxfd) {
73 unsigned long nn = poll_maxfd + 4;
74 poll_fds = p_realloc(poll_fds, sizeof(struct pollfd)*nn);
75 poll_handler = p_realloc(poll_handler, sizeof(u_handler)*nn);
76 poll_maxfd = nn;
77 }
78 poll_fds[poll_nfds].fd = fd;
79 poll_fds[poll_nfds].events = POLLIN | POLLPRI;
80 poll_fds[poll_nfds].revents = 0;
81 poll_handler[poll_nfds].callback = callback;
82 poll_handler[poll_nfds].context = context;
83 poll_nfds++;
84 u_fdwatch(fd, 1);
85
86 } else {
87 int i;
88 int n = poll_nfds-1;
89 for (i=0 ; i<poll_nfds ; i++)
90 if (poll_fds[i].fd==fd) {
91 /* CRITICAL section */
92 if (n) {
93 poll_handler[i].callback = poll_handler[n].callback;
94 poll_handler[i].context = poll_handler[n].context;
95 poll_fds[i].fd = poll_fds[n].fd;
96 }
97 poll_nfds = n;
98 break;
99 }
100 }
101 }
102
103 void
u_prepoll(int (* conditional)(void *),void * context)104 u_prepoll(int (*conditional)(void *), void *context)
105 {
106 if (conditional) {
107 if (prepoll_n>=prepoll_mx) {
108 prepoll = p_realloc(prepoll, sizeof(u_prehandler)*(prepoll_mx+4));
109 prepoll_mx += 4;
110 }
111 prepoll[prepoll_n].conditional = conditional;
112 prepoll[prepoll_n].context = context;
113 prepoll_n++;
114
115 } else {
116 int i;
117 int n = prepoll_n-1;
118 for (i=0 ; i<prepoll_n ; i++)
119 if (prepoll[i].context==context) {
120 /* CRITICAL section */
121 if (n) {
122 prepoll[i].conditional = prepoll[n].conditional;
123 prepoll[i].context = prepoll[n].context;
124 }
125 prepoll_n = n;
126 break;
127 }
128 }
129 }
130
131 int
u_poll(int timeout)132 u_poll(int timeout)
133 {
134 int i, n = 0;
135
136 /* check prepolling conditionals first
137 * prepoll_i counter makes this happen in round-robin fashion,
138 * so the first one won't get all the calls */
139 for (i=prepoll_n ; i-- ; ) {
140 if ((++prepoll_i) >= prepoll_n) prepoll_i = 0;
141 if (prepoll[prepoll_i].conditional(prepoll[prepoll_i].context))
142 return 1;
143 }
144
145 /* refuse to wait forever with no event sources */
146 if (!poll_nfds && timeout<0) return -3;
147 /* work around bug in MacOS 10.3 poll function */
148 if (!poll_fds) poll_fds = p_malloc(sizeof(struct pollfd));
149
150 /* check for any events which arrived on previous poll before
151 * calling poll again -- assures that first fd in poll_fds cannot
152 * prevent any other fd from being serviced */
153 do {
154 for (i=0 ; i<poll_nfds ; i++)
155 if (poll_fds[i].revents & (POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL)) {
156 poll_fds[i].revents = 0;
157 poll_handler[i].callback(poll_handler[i].context);
158 return 1;
159 }
160 if (n) return -2;
161
162 if (timeout<0) timeout = -1;
163 n = u__poll(poll_fds, poll_nfds, timeout);
164 if (n<0 && errno==EINTR) n = 0;
165 } while (n>0);
166
167 return n;
168 }
169
170 /* required by x11 to wait only finite time for X selection response */
171 int
u_poll1(int fd,int timeout)172 u_poll1(int fd, int timeout)
173 {
174 int n;
175 struct pollfd pfd;
176 pfd.fd = fd;
177 pfd.events = POLLIN | POLLPRI;
178 pfd.revents = 0;
179 n = u__poll(&pfd, (unsigned long)1, timeout);
180 if (n<0 && errno!=EINTR) return n;
181 return n>0;
182 }
183