LCOV - code coverage report
Current view: top level - src/unix - ufdwatch.c (source / functions) Hit Total Coverage
Test: allegro_auto.info Lines: 0 47 0.0 %
Date: 2018-08-11 00:50:28 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*         ______   ___    ___ 
       2             :  *        /\  _  \ /\_ \  /\_ \ 
       3             :  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
       4             :  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
       5             :  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
       6             :  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
       7             :  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
       8             :  *                                           /\____/
       9             :  *                                           \_/__/
      10             :  *
      11             :  *      Unix fd watcher thread.
      12             :  *
      13             :  *      By Peter Wang.
      14             :  *
      15             :  *      See readme.txt for copyright information.
      16             :  *
      17             :  *      This module implements a background thread that waits for data
      18             :  *      to arrive in file descriptors, at which point it dispatches to
      19             :  *      functions which will process that data.
      20             :  */
      21             : 
      22             : 
      23             : #include <pthread.h>
      24             : #include <stdlib.h>
      25             : #include <sys/types.h>
      26             : #include <sys/select.h>
      27             : #include <unistd.h>
      28             : 
      29             : #include "allegro5/allegro.h"
      30             : #include "allegro5/internal/aintern.h"
      31             : #include "allegro5/internal/aintern_thread.h"
      32             : #include "allegro5/internal/aintern_vector.h"
      33             : #include "allegro5/platform/aintunix.h"
      34             : 
      35             : 
      36             : 
      37             : typedef struct WATCH_ITEM
      38             : {
      39             :    int fd;
      40             :    void (*callback)(void *);
      41             :    void *cb_data;
      42             : } WATCH_ITEM;
      43             : 
      44             : 
      45             : static _AL_THREAD fd_watch_thread;
      46             : static _AL_MUTEX fd_watch_mutex = _AL_MUTEX_UNINITED;
      47             : static _AL_VECTOR fd_watch_list = _AL_VECTOR_INITIALIZER(WATCH_ITEM);
      48             : 
      49             : 
      50             : 
      51             : /* fd_watch_thread_func: [fdwatch thread]
      52             :  *  The thread loop function.
      53             :  */
      54           0 : static void fd_watch_thread_func(_AL_THREAD *self, void *unused)
      55             : {
      56             :    (void)unused;
      57             : 
      58           0 :    while (!_al_get_thread_should_stop(self)) {
      59             : 
      60             :       fd_set rfds;
      61             :       int max_fd;
      62             : 
      63             :       /* set up max_fd and rfds */
      64           0 :       _al_mutex_lock(&fd_watch_mutex);
      65             :       {
      66             :          WATCH_ITEM *wi;
      67             :          unsigned int i;
      68             : 
      69           0 :          FD_ZERO(&rfds);
      70           0 :          max_fd = -1;
      71             : 
      72           0 :          for (i = 0; i < _al_vector_size(&fd_watch_list); i++) {
      73           0 :             wi = _al_vector_ref(&fd_watch_list, i);
      74           0 :             FD_SET(wi->fd, &rfds);
      75           0 :             if (wi->fd > max_fd)
      76           0 :                max_fd = wi->fd;
      77             :          }
      78             :       }
      79           0 :       _al_mutex_unlock(&fd_watch_mutex);
      80             : 
      81             :       /* wait for something to happen on one of the fds */
      82             :       {
      83             :          struct timeval tv;
      84             :          int retval;
      85             : 
      86           0 :          tv.tv_sec = 0;
      87           0 :          tv.tv_usec = 250000;
      88             : 
      89           0 :          retval = select(max_fd+1, &rfds, NULL, NULL, &tv);
      90           0 :          if (retval < 1)
      91           0 :             continue;
      92             :       }
      93             : 
      94             :       /* one or more of the fds has activity */
      95             :       _al_mutex_lock(&fd_watch_mutex);
      96             :       {
      97             :          WATCH_ITEM *wi;
      98             :          unsigned int i;
      99             : 
     100           0 :          for (i = 0; i < _al_vector_size(&fd_watch_list); i++) {
     101           0 :             wi = _al_vector_ref(&fd_watch_list, i);
     102           0 :             if (FD_ISSET(wi->fd, &rfds)) {
     103             :                /* The callback is allowed to modify the watch list so the mutex
     104             :                 * must be recursive.
     105             :                 */
     106           0 :                wi->callback(wi->cb_data);
     107             :             }
     108             :          }
     109             :       }
     110           0 :       _al_mutex_unlock(&fd_watch_mutex);
     111             :    }
     112           0 : }
     113             : 
     114             : 
     115             : 
     116             : /* _al_unix_start_watching_fd: [primary thread]
     117             :  * 
     118             :  *  Start watching for data on file descriptor `fd'.  This is done in
     119             :  *  a background thread, which is started if necessary.  When there is
     120             :  *  data waiting to be read on fd, `callback' is applied to `cb_data'.
     121             :  *  The callback function should read as much data off fd as possible.
     122             :  *
     123             :  *  Note: the callback is run from the background thread.  You can
     124             :  *  assume there is only one callback being called from the fdwatch
     125             :  *  module at a time.
     126             :  */
     127           0 : void _al_unix_start_watching_fd(int fd, void (*callback)(void *), void *cb_data)
     128             : {
     129             :    ASSERT(fd >= 0);
     130             :    ASSERT(callback);
     131             : 
     132             :    /* start the background thread if necessary */
     133           0 :    if (_al_vector_size(&fd_watch_list) == 0) {
     134             :       /* We need a recursive mutex to allow callbacks to modify the fd watch
     135             :        * list.
     136             :        */
     137           0 :       _al_mutex_init_recursive(&fd_watch_mutex);
     138           0 :       _al_thread_create(&fd_watch_thread, fd_watch_thread_func, NULL);
     139             :    }
     140             : 
     141             :    /* now add the watch item to the list */
     142           0 :    _al_mutex_lock(&fd_watch_mutex);
     143             :    {
     144           0 :       WATCH_ITEM *wi = _al_vector_alloc_back(&fd_watch_list);
     145             : 
     146           0 :       wi->fd = fd;
     147           0 :       wi->callback = callback;
     148           0 :       wi->cb_data = cb_data;
     149             :    }
     150           0 :    _al_mutex_unlock(&fd_watch_mutex);
     151           0 : }
     152             : 
     153             : 
     154             : 
     155             : /* _al_unix_stop_watching_fd: [primary thread]
     156             :  *
     157             :  *  Stop watching for data on `fd'.  Once there are no more file
     158             :  *  descriptors to watch, the background thread will be stopped.  This
     159             :  *  function is synchronised with the background thread, so you don't
     160             :  *  have to do any locking before calling it.
     161             :  */
     162           0 : void _al_unix_stop_watching_fd(int fd)
     163             : {
     164           0 :    bool list_empty = false;
     165             : 
     166             :    /* find the fd in the watch list and remove it */
     167             :    _al_mutex_lock(&fd_watch_mutex);
     168             :    {
     169             :       WATCH_ITEM *wi;
     170             :       unsigned int i;
     171             : 
     172           0 :       for (i = 0; i < _al_vector_size(&fd_watch_list); i++) {
     173           0 :          wi = _al_vector_ref(&fd_watch_list, i);
     174           0 :          if (wi->fd == fd) {
     175           0 :             _al_vector_delete_at(&fd_watch_list, i);
     176           0 :             list_empty = _al_vector_is_empty(&fd_watch_list);
     177           0 :             break;
     178             :          }
     179             :       }
     180             :    }
     181           0 :    _al_mutex_unlock(&fd_watch_mutex);
     182             : 
     183             :    /* if no more fd's are being watched, stop the background thread */
     184           0 :    if (list_empty) {
     185           0 :       _al_thread_join(&fd_watch_thread);
     186           0 :       _al_mutex_destroy(&fd_watch_mutex);
     187           0 :       _al_vector_free(&fd_watch_list);
     188             :    }
     189           0 : }
     190             : 
     191             : 
     192             : 
     193             : /*
     194             :  * Local Variables:
     195             :  * c-basic-offset: 3
     196             :  * indent-tabs-mode: nil
     197             :  * End:
     198             :  */

Generated by: LCOV version 1.13