wmclockmon: update change-log
[dockapps.git] / wmget / dockapp / da_run.c
bloba0ff6b22d0545a0ab9a877520266b07d64ef3566
1 /*
2 wmget - A background download manager as a Window Maker dock app
3 Copyright (c) 2001-2003 Aaron Trickey <aaron@amtrickey.net>
5 Permission is hereby granted, free of charge, to any person
6 obtaining a copy of this software and associated documentation files
7 (the "Software"), to deal in the Software without restriction,
8 including without limitation the rights to use, copy, modify, merge,
9 publish, distribute, sublicense, and/or sell copies of the Software,
10 and to permit persons to whom the Software is furnished to do so,
11 subject to the following conditions:
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 ********************************************************************
25 dockapp/da_run.c - Main dockapp loop; fd polling; periodic callback
27 This file implements dockapp_run(), which provides the main loop of
28 the dockapp application. In addition, it implements
29 dockapp_add_pollfd(), which adds polling of arbitrary file
30 descriptors to the main loop, and dockapp_set_periodic_callback(),
31 which sets up a periodic app callback.
34 #include <string.h>
35 #include <assert.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <sys/time.h>
40 #include <sys/poll.h>
42 #include "dockapp.h"
45 /* we keep two parallel structures... one, the list of pollfd's for
46 * poll(2)'s benefit, and the other, the collection of callback
47 * information
49 typedef struct {
50 dockapp_rv_t (*cb) (void *cbdata, short revents);
51 void *cbdata;
52 short revents;
53 } da_pollcb;
56 enum {
57 da_max_pollfds = 50
60 static struct pollfd da_pollfds[da_max_pollfds];
61 static da_pollcb da_pollcbs[da_max_pollfds];
62 static int da_num_pollfds = 0;
65 dockapp_rv_t dockapp_add_pollfd (
66 int fd,
67 short pollevents,
68 dockapp_rv_t (*cb) (void *, short pollstatus),
69 void *cbdata)
71 struct pollfd *pfd;
72 da_pollcb *pcb;
74 assert (da_num_pollfds < da_max_pollfds);
77 fprintf (stderr, "adding pollfd #%d, fd = %d, events = %hu\n",
78 da_num_pollfds, fd, pollevents);
81 pfd = da_pollfds + da_num_pollfds;
82 pcb = da_pollcbs + da_num_pollfds;
84 pfd->fd = fd;
85 pfd->events = pollevents;
86 pcb->cb = cb;
87 pcb->cbdata = cbdata;
89 ++da_num_pollfds;
91 return dockapp_ok;
95 dockapp_rv_t dockapp_remove_pollfd (
96 int fd)
98 int i = da_num_pollfds;
99 struct pollfd *pfd = da_pollfds;
100 da_pollcb *pcb = da_pollcbs;
102 for ( ; i; --i, ++pfd, ++pcb) {
103 if (pfd->fd == fd) {
104 memmove (pfd, pfd + 1, (i - 1) * sizeof (struct pollfd));
105 memmove (pcb, pcb + 1, (i - 1) * sizeof (da_pollcb));
106 return dockapp_ok;
110 /* not found... */
111 return dockapp_invalid_arg;
115 /* periodic callback info... if da_timer_cb is null, then no callback is
116 * set.
118 static dockapp_rv_t (*da_timer_cb) (void *) = 0;
119 static void *da_timer_cbdata;
120 static struct timeval da_timer_next_timeout;
121 static long da_timer_interval_msec;
124 static void da_reset_timer (void)
126 int rv;
128 rv = gettimeofday (&da_timer_next_timeout, 0);
129 assert (rv == 0);
132 fprintf (stderr,
133 "da_reset_timer: RIGHT NOW is %ld.%ld, msec = %ld\n",
134 da_timer_next_timeout.tv_sec,
135 da_timer_next_timeout.tv_usec,
136 da_timer_interval_msec);
139 da_timer_next_timeout.tv_usec
140 += (da_timer_interval_msec % 1000L) * 1000L;
142 da_timer_next_timeout.tv_sec
143 += da_timer_interval_msec / 1000L
144 + da_timer_next_timeout.tv_usec / 1000000L;
146 da_timer_next_timeout.tv_usec %= 1000000L;
149 fprintf (stderr,
150 "da_reset_timer: NEXT TIMEOUT is %ld.%ld\n",
151 da_timer_next_timeout.tv_sec,
152 da_timer_next_timeout.tv_usec);
157 static long da_timer_msec_remaining (void)
159 struct timeval right_now;
160 int rv;
162 rv = gettimeofday (&right_now, 0);
164 return
165 (da_timer_next_timeout.tv_sec - right_now.tv_sec) * 1000L
166 + (da_timer_next_timeout.tv_usec - right_now.tv_usec) / 1000L;
170 void dockapp_set_periodic_callback (
171 long msec,
172 dockapp_rv_t (*cb) (void *),
173 void *cbdata)
175 da_timer_cb = cb;
176 da_timer_cbdata = cbdata;
178 da_timer_interval_msec = msec;
180 da_reset_timer ();
184 void dockapp_remove_periodic_callback (void)
186 da_timer_cb = 0;
187 da_timer_cbdata = 0;
188 da_timer_interval_msec = 0;
192 /* this is the main loop for the dockapp...
194 dockapp_rv_t dockapp_run (void)
196 for ( ; ; ) {
197 int rv;
198 int poll_timeout = -1; /* infinite unless periodic callback */
200 if (da_timer_cb) {
201 if (da_timer_msec_remaining () <= 0) {
202 rv = da_timer_cb (da_timer_cbdata);
203 da_reset_timer ();
206 poll_timeout = da_timer_msec_remaining ();
210 fprintf (stderr, "about to poll(%d fd, %d timeout)\n",
211 da_num_pollfds, poll_timeout);
214 rv = poll (da_pollfds, da_num_pollfds, poll_timeout);
217 fprintf (stderr, "poll returned %d\n", rv);
220 if (rv == 0) {
221 /* poll timed out; let's loop back up and let the logic
222 * prior to the poll() invoke the user-defined periodic
223 * callback
225 continue;
226 } else if (rv < 0) {
227 /* Disregard EINTR; just means that a signal was caught.
228 * We'll retry later.
230 if (errno != EINTR)
231 perror ("poll()");
233 } else {
234 /* poll returned with some nonzero number of events...
235 * collect the callback structures first, then invoke the
236 * callbacks, since the callback functions are allowed to
237 * create and destroy callbacks as well
239 int i;
240 da_pollcb callbacks[da_max_pollfds];
241 da_pollcb *c;
242 int ncallbacks = 0;
244 for (i = 0; i < da_num_pollfds && ncallbacks < rv; ++i) {
245 if (da_pollfds[i].revents) {
246 callbacks[ncallbacks] = da_pollcbs[i];
247 callbacks[ncallbacks].revents
248 = da_pollfds[i].revents;
249 ++ncallbacks;
253 for (c = callbacks; ncallbacks; --ncallbacks, ++c) {
254 if (c->cb (c->cbdata, c->revents) == dockapp_exit) {
255 fprintf (stderr, "exiting dockapp_run()\n");
256 return dockapp_ok;