expand tabs
[platform/upstream/gstreamer.git] / gst / tcp / gstfdset.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
4  *
5  * gsttcpfdset.h: fdset datastructure
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #define MIN_POLLFDS     32
24 #define INIT_POLLFDS    MIN_POLLFDS
25
26 #include <sys/poll.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 /* OS/X needs this because of bad headers */
31 #include <string.h>
32
33 #include "gstfdset.h"
34
35 GType
36 gst_fdset_mode_get_type (void)
37 {
38   static GType fdset_mode_type = 0;
39   static GEnumValue fdset_mode[] = {
40     {GST_FDSET_MODE_SELECT, "Select", "select"},
41     {GST_FDSET_MODE_POLL, "Poll", "poll"},
42     {GST_FDSET_MODE_EPOLL, "EPoll", "epoll"},
43     {0, NULL, NULL},
44   };
45
46   if (!fdset_mode_type) {
47     fdset_mode_type = g_enum_register_static ("GstFDSetMode", fdset_mode);
48   }
49   return fdset_mode_type;
50 }
51
52 struct _GstFDSet
53 {
54   GstFDSetMode mode;
55
56   /* for poll */
57   struct pollfd *testpollfds;
58   gint last_testpollfds;
59   gint testsize;
60
61   struct pollfd *pollfds;
62   gint size;
63   gint free;
64   gint last_pollfds;
65   GMutex *poll_lock;
66
67   /* for select */
68   fd_set readfds, writefds;     /* input */
69   fd_set testreadfds, testwritefds;     /* output */
70 };
71
72 static gint
73 nearest_pow (gint num)
74 {
75   /* hacker's delight page 48 */
76   num -= 1;
77   num |= num >> 1;
78   num |= num >> 2;
79   num |= num >> 4;
80   num |= num >> 8;
81   num |= num >> 16;
82
83   return num + 1;
84 }
85
86 /* resize a given pollfd array from old_size number of items
87  * to new_size number of items. Also initializes the new elements
88  * with the default values. */
89 static struct pollfd *
90 resize (struct pollfd *fds, gint old_size, gint new_size)
91 {
92   struct pollfd *res;
93   gint i;
94
95   res = g_realloc (fds, new_size * sizeof (struct pollfd));
96   for (i = old_size; i < new_size; i++) {
97     res[i].fd = -1;
98     res[i].events = 0;
99     res[i].revents = 0;
100   }
101   return res;
102 }
103
104 static void
105 ensure_size (GstFDSet * set, gint len)
106 {
107   if (len > set->size) {
108     len = nearest_pow (len);
109     len = MAX (len, MIN_POLLFDS);
110
111     set->pollfds = resize (set->pollfds, set->size, len);
112     set->size = len;
113   }
114 }
115
116 GstFDSet *
117 gst_fdset_new (GstFDSetMode mode)
118 {
119   GstFDSet *nset;
120
121   nset = g_new0 (GstFDSet, 1);
122   nset->mode = mode;
123
124   switch (mode) {
125     case GST_FDSET_MODE_SELECT:
126       FD_ZERO (&nset->readfds);
127       FD_ZERO (&nset->writefds);
128       break;
129     case GST_FDSET_MODE_POLL:
130       nset->pollfds = NULL;
131       nset->testpollfds = NULL;
132       nset->free = 0;
133       nset->last_pollfds = 0;
134       nset->poll_lock = g_mutex_new ();
135       ensure_size (nset, MIN_POLLFDS);
136       break;
137     case GST_FDSET_MODE_EPOLL:
138       g_warning ("implement EPOLL mode in GstFDSet");
139       break;
140     default:
141       break;
142   }
143   return nset;
144 }
145
146 void
147 gst_fdset_free (GstFDSet * set)
148 {
149   g_return_if_fail (set != NULL);
150
151   switch (set->mode) {
152     case GST_FDSET_MODE_SELECT:
153       break;
154     case GST_FDSET_MODE_POLL:
155       g_free (set->testpollfds);
156       g_free (set->pollfds);
157       g_mutex_free (set->poll_lock);
158       break;
159     case GST_FDSET_MODE_EPOLL:
160       g_warning ("implement EPOLL mode in GstFDSet");
161       break;
162     default:
163       break;
164   }
165   g_free (set);
166 }
167
168
169 void
170 gst_fdset_set_mode (GstFDSet * set, GstFDSetMode mode)
171 {
172   g_return_if_fail (set != NULL);
173
174   g_warning ("implement set_mode in GstFDSet");
175 }
176
177 GstFDSetMode
178 gst_fdset_get_mode (GstFDSet * set)
179 {
180   g_return_val_if_fail (set != NULL, FALSE);
181
182   return set->mode;
183 }
184
185 gboolean
186 gst_fdset_add_fd (GstFDSet * set, GstFD * fd)
187 {
188   gboolean res = FALSE;
189
190   g_return_val_if_fail (set != NULL, FALSE);
191   g_return_val_if_fail (fd != NULL, FALSE);
192
193   switch (set->mode) {
194     case GST_FDSET_MODE_SELECT:
195       res = TRUE;
196       break;
197     case GST_FDSET_MODE_POLL:
198     {
199       struct pollfd *nfd;
200       gint idx;
201
202       g_mutex_lock (set->poll_lock);
203
204       ensure_size (set, set->last_pollfds + 1);
205
206       idx = set->free;
207       if (idx == -1) {
208         /* find free space */
209         while (idx < set->last_pollfds) {
210           idx++;
211           if (set->pollfds[idx].fd == -1)
212             break;
213         }
214       }
215       nfd = &set->pollfds[idx];
216
217       nfd->fd = fd->fd;
218       nfd->events = POLLERR | POLLNVAL | POLLHUP;
219       nfd->revents = 0;
220
221       /* see if we have one fd more */
222       set->last_pollfds = MAX (idx + 1, set->last_pollfds);
223       fd->idx = idx;
224       set->free = -1;
225       g_mutex_unlock (set->poll_lock);
226
227       res = TRUE;
228       break;
229     }
230     case GST_FDSET_MODE_EPOLL:
231       break;
232   }
233   return res;
234 }
235
236 gboolean
237 gst_fdset_remove_fd (GstFDSet * set, GstFD * fd)
238 {
239   gboolean res = FALSE;
240
241   g_return_val_if_fail (set != NULL, FALSE);
242   g_return_val_if_fail (fd != NULL, FALSE);
243
244   switch (set->mode) {
245     case GST_FDSET_MODE_SELECT:
246       /* nothing */
247       FD_CLR (fd->fd, &set->writefds);
248       FD_CLR (fd->fd, &set->readfds);
249       res = TRUE;
250       break;
251     case GST_FDSET_MODE_POLL:
252     {
253       g_mutex_lock (set->poll_lock);
254
255       /* FIXME on some platforms poll doesn't ignore the fd
256        * when set to -1 */
257       set->pollfds[fd->idx].fd = -1;
258       set->pollfds[fd->idx].events = 0;
259       set->pollfds[fd->idx].revents = 0;
260
261       /* if we removed the last fd, we can lower the last_pollfds */
262       if (fd->idx + 1 == set->last_pollfds) {
263         set->last_pollfds--;
264       }
265       fd->idx = -1;
266
267       if (set->free == -1) {
268         set->free = fd->idx;
269       } else {
270         set->free = MIN (set->free, fd->idx);
271       }
272       g_mutex_unlock (set->poll_lock);
273       res = TRUE;
274       break;
275     }
276     case GST_FDSET_MODE_EPOLL:
277       break;
278   }
279   return res;
280 }
281
282 void
283 gst_fdset_fd_ctl_write (GstFDSet * set, GstFD * fd, gboolean active)
284 {
285   g_return_if_fail (set != NULL);
286   g_return_if_fail (fd != NULL);
287
288   switch (set->mode) {
289     case GST_FDSET_MODE_SELECT:
290       if (active)
291         FD_SET (fd->fd, &set->writefds);
292       else
293         FD_CLR (fd->fd, &set->writefds);
294       break;
295     case GST_FDSET_MODE_POLL:
296     {
297       gint idx;
298
299       g_mutex_lock (set->poll_lock);
300
301       idx = fd->idx;
302       if (idx >= 0) {
303         gint events = set->pollfds[idx].events;
304
305         if (active)
306           events |= POLLOUT;
307         else
308           events &= ~POLLOUT;
309
310         set->pollfds[idx].events = events;
311       }
312       g_mutex_unlock (set->poll_lock);
313       break;
314     }
315     case GST_FDSET_MODE_EPOLL:
316       break;
317   }
318 }
319
320 void
321 gst_fdset_fd_ctl_read (GstFDSet * set, GstFD * fd, gboolean active)
322 {
323   g_return_if_fail (set != NULL);
324   g_return_if_fail (fd != NULL);
325
326   switch (set->mode) {
327     case GST_FDSET_MODE_SELECT:
328       if (active)
329         FD_SET (fd->fd, &set->readfds);
330       else
331         FD_CLR (fd->fd, &set->readfds);
332       break;
333     case GST_FDSET_MODE_POLL:
334     {
335       gint idx;
336
337       g_mutex_lock (set->poll_lock);
338
339       idx = fd->idx;
340       if (idx >= 0) {
341         gint events = set->pollfds[idx].events;
342
343         if (active)
344           events |= (POLLIN | POLLPRI);
345         else
346           events &= ~(POLLIN | POLLPRI);
347
348         set->pollfds[idx].events = events;
349       }
350       g_mutex_unlock (set->poll_lock);
351       break;
352     }
353     case GST_FDSET_MODE_EPOLL:
354       break;
355   }
356 }
357
358 gboolean
359 gst_fdset_fd_has_closed (GstFDSet * set, GstFD * fd)
360 {
361   gboolean res = FALSE;
362
363   g_return_val_if_fail (set != NULL, FALSE);
364   g_return_val_if_fail (fd != NULL, FALSE);
365
366   switch (set->mode) {
367     case GST_FDSET_MODE_SELECT:
368       res = FALSE;
369       break;
370     case GST_FDSET_MODE_POLL:
371     {
372       gint idx;
373
374       g_mutex_lock (set->poll_lock);
375       idx = fd->idx;
376
377       if (idx >= 0 && idx < set->last_testpollfds) {
378         res = (set->testpollfds[idx].revents & POLLHUP) != 0;
379       }
380       g_mutex_unlock (set->poll_lock);
381       break;
382     }
383     case GST_FDSET_MODE_EPOLL:
384       break;
385   }
386   return res;
387 }
388
389 gboolean
390 gst_fdset_fd_has_error (GstFDSet * set, GstFD * fd)
391 {
392   gboolean res = FALSE;
393
394   g_return_val_if_fail (set != NULL, FALSE);
395   g_return_val_if_fail (fd != NULL, FALSE);
396
397   switch (set->mode) {
398     case GST_FDSET_MODE_SELECT:
399       res = FALSE;
400       break;
401     case GST_FDSET_MODE_POLL:
402     {
403       gint idx;
404
405       g_mutex_lock (set->poll_lock);
406       idx = fd->idx;
407
408       if (idx >= 0 && idx < set->last_testpollfds) {
409         res = (set->testpollfds[idx].revents & (POLLERR | POLLNVAL)) != 0;
410       }
411       g_mutex_unlock (set->poll_lock);
412       break;
413     }
414     case GST_FDSET_MODE_EPOLL:
415       break;
416   }
417   return res;
418 }
419
420 gboolean
421 gst_fdset_fd_can_read (GstFDSet * set, GstFD * fd)
422 {
423   gboolean res = FALSE;
424
425   g_return_val_if_fail (set != NULL, FALSE);
426   g_return_val_if_fail (fd != NULL, FALSE);
427
428   switch (set->mode) {
429     case GST_FDSET_MODE_SELECT:
430       res = FD_ISSET (fd->fd, &set->testreadfds);
431       break;
432     case GST_FDSET_MODE_POLL:
433     {
434       gint idx;
435
436       g_mutex_lock (set->poll_lock);
437       idx = fd->idx;
438
439       if (idx >= 0 && idx < set->last_testpollfds) {
440         res = (set->testpollfds[idx].revents & (POLLIN | POLLPRI)) != 0;
441       }
442       g_mutex_unlock (set->poll_lock);
443       break;
444     }
445     case GST_FDSET_MODE_EPOLL:
446       break;
447   }
448   return res;
449 }
450
451 gboolean
452 gst_fdset_fd_can_write (GstFDSet * set, GstFD * fd)
453 {
454   gboolean res = FALSE;
455
456   g_return_val_if_fail (set != NULL, FALSE);
457   g_return_val_if_fail (fd != NULL, FALSE);
458
459   switch (set->mode) {
460     case GST_FDSET_MODE_SELECT:
461       res = FD_ISSET (fd->fd, &set->testwritefds);
462       break;
463     case GST_FDSET_MODE_POLL:
464     {
465       gint idx;
466
467       g_mutex_lock (set->poll_lock);
468       idx = fd->idx;
469
470       if (idx >= 0 && idx < set->last_testpollfds) {
471         res = (set->testpollfds[idx].revents & POLLOUT) != 0;
472       }
473       g_mutex_unlock (set->poll_lock);
474       break;
475     }
476     case GST_FDSET_MODE_EPOLL:
477       break;
478   }
479   return res;
480 }
481
482 gint
483 gst_fdset_wait (GstFDSet * set, int timeout)
484 {
485   int res = -1;
486
487   g_return_val_if_fail (set != NULL, -1);
488
489   switch (set->mode) {
490     case GST_FDSET_MODE_SELECT:
491     {
492       struct timeval tv;
493       struct timeval *tvptr;
494
495       set->testreadfds = set->readfds;
496       set->testwritefds = set->writefds;
497
498       if (timeout > 0) {
499         tv.tv_sec = timeout / 1000;
500         tv.tv_usec = timeout % 1000;
501
502         tvptr = &tv;
503       } else {
504         tvptr = NULL;
505       }
506       res =
507           select (FD_SETSIZE, &set->testreadfds, &set->testwritefds,
508           (fd_set *) 0, tvptr);
509       break;
510     }
511     case GST_FDSET_MODE_POLL:
512     {
513       g_mutex_lock (set->poll_lock);
514       if (set->testsize != set->size) {
515         set->testpollfds = resize (set->testpollfds, set->testsize, set->size);
516         set->testsize = set->size;
517       }
518       set->last_testpollfds = set->last_pollfds;
519       memcpy (set->testpollfds, set->pollfds,
520           sizeof (struct pollfd) * set->last_testpollfds);
521       g_mutex_unlock (set->poll_lock);
522
523       res = poll (set->testpollfds, set->last_testpollfds, timeout);
524
525       break;
526     }
527     case GST_FDSET_MODE_EPOLL:
528       break;
529   }
530
531   return res;
532 }