udphole

Basic UDP wormhole proxy
git clone git://git.finwo.net/app/udphole
Log | Files | Refs | README | LICENSE

scheduler.c (3210B)


      1 #include <stdlib.h>
      2 #include <sys/select.h>
      3 #include <sys/time.h>
      4 
      5 #include "rxi/log.h"
      6 #include "domain/scheduler.h"
      7 
      8 #ifndef NULL
      9 #define NULL ((void*)0)
     10 #endif
     11 
     12 pt_task_t *pt_first = NULL;
     13 fd_set g_select_result;
     14 static fd_set g_want_fds;
     15 
     16 int domain_schedmod_pt_create(pt_task_fn fn, void *udata) {
     17   if (!fn) return 1;
     18 
     19   pt_task_t *node = calloc(1, sizeof(pt_task_t));
     20   node->next           = pt_first;
     21   node->func           = fn;
     22   node->udata          = udata;
     23   PT_INIT(&node->pt);
     24   node->is_active  = 1;
     25   pt_first = node;
     26   
     27   log_trace("scheduler: created task %p (func=%p, udata=%p), pt_first=%p", (void*)node, (void*)fn, udata, (void*)pt_first);
     28 
     29   return 0;
     30 }
     31 
     32 int domain_schedmod_pt_remove(pt_task_t *task) {
     33   if (!task) return 1;
     34 
     35   pt_task_t *curr = pt_first;
     36   pt_task_t *prev = NULL;
     37 
     38   while (curr) {
     39     if (curr == task) {
     40       if (prev) {
     41         prev->next = curr->next;
     42       } else {
     43         pt_first = curr->next;
     44       }
     45       free(curr);
     46       return 0;
     47     }
     48     prev = curr;
     49     curr = curr->next;
     50   }
     51 
     52   return 1;
     53 }
     54 
     55 int domain_schedmod_has_data(int *in_fds, int **out_fds) {
     56   if (!in_fds || in_fds[0] == 0) return 0;
     57   log_trace("domain_schedmod_has_data: in_fds[0]=%d", in_fds[0]);
     58 
     59   for (int i = 1; i <= in_fds[0]; i++) {
     60     int fd = in_fds[i];
     61     if (fd >= 0) {
     62       FD_SET(fd, &g_want_fds);
     63     }
     64   }
     65 
     66   if (*out_fds) free(*out_fds);
     67   *out_fds = NULL;
     68 
     69   int count = 0;
     70   for (int i = 1; i <= in_fds[0]; i++) {
     71     if (in_fds[i] >= 0 && FD_ISSET(in_fds[i], &g_select_result)) {
     72       count++;
     73     }
     74   }
     75 
     76   if (count == 0) return 0;
     77 
     78   *out_fds = malloc(sizeof(int) * (count + 1));
     79   if (!*out_fds) return 0;
     80 
     81   (*out_fds)[0] = count;
     82   int idx = 1;
     83   for (int i = 1; i <= in_fds[0]; i++) {
     84     if (in_fds[i] >= 0 && FD_ISSET(in_fds[i], &g_select_result)) {
     85       (*out_fds)[idx++] = in_fds[i];
     86       FD_CLR(in_fds[i], &g_select_result);
     87     }
     88   }
     89 
     90   return count;
     91 }
     92 
     93 int domain_schedmod_main(void) {
     94   if (!pt_first) return 0;
     95 
     96   struct timeval tv;
     97   int maxfd = -1;
     98 
     99   for(;;) {
    100     maxfd = -1;
    101     for (int fd = 0; fd < FD_SETSIZE; fd++) {
    102       if (FD_ISSET(fd, &g_want_fds)) {
    103         if (fd > maxfd) maxfd = fd;
    104       }
    105     }
    106 
    107 
    108     tv.tv_sec = 0;
    109     tv.tv_usec = 100000;
    110     select(maxfd + 1, &g_want_fds, NULL, NULL, &tv);
    111     log_trace("scheduler: select returned");
    112 
    113     struct timeval now;
    114     gettimeofday(&now, NULL);
    115     int64_t timestamp = (int64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
    116     g_select_result = g_want_fds;
    117 
    118     FD_ZERO(&g_want_fds);
    119 
    120   pt_task_t *task = pt_first;
    121   while (task) {
    122     pt_task_t *next = task->next;
    123     log_trace("scheduler: about to run task %p (func=%p, is_active=%d)", (void*)task, (void*)task->func, task->is_active);
    124     task->is_active = PT_SCHEDULE(task->func(&task->pt, timestamp, task));
    125     log_trace("scheduler: task %p (func=%p) returned, is_active=%d, next=%p", (void*)task, (void*)task->func, task->is_active, (void*)next);
    126     if (!task->is_active) {
    127       log_trace("scheduler: removing inactive task %p", (void*)task);
    128       domain_schedmod_pt_remove(task);
    129     }
    130     task = next;
    131   }
    132   log_trace("scheduler: loop done, pt_first=%p", (void*)pt_first);
    133 
    134     if (!pt_first) break;
    135   }
    136 
    137   return 0;
    138 }