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