Fork me on GitHub

root/kernel/syscalls/select.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_fds
  2. do_check
  3. do_select
  4. sys_select

   1 /*
   2  * fiwix/kernel/syscalls/select.c
   3  *
   4  * Copyright 2018, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/types.h>
   9 #include <fiwix/fs.h>
  10 #include <fiwix/process.h>
  11 #include <fiwix/timer.h>
  12 #include <fiwix/sched.h>
  13 #include <fiwix/sleep.h>
  14 #include <fiwix/errno.h>
  15 #include <fiwix/stdio.h>
  16 #include <fiwix/string.h>
  17 
  18 static int check_fds(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds)
  19 {
  20         int n, bit;
  21         unsigned long int set;
  22 
  23         n = bit = 0;
  24         while(bit < nfds) {
  25                 bit = n * __NFDBITS;
  26                 set = rfds->fds_bits[n] | wfds->fds_bits[n] | efds->fds_bits[n];
  27                 while(set) {
  28                         if(__FD_ISSET(bit, rfds)) {
  29                                 CHECK_UFD(bit);
  30                         }
  31                         set >>= 1;
  32                         bit++;
  33                 }
  34                 n++;
  35         }
  36 
  37         return 0;
  38 }
  39 
  40 static int do_check(struct inode *i, int flag)
  41 {
  42         if(i->fsop && i->fsop->select) {
  43                 if(i->fsop->select(i, flag)) {
  44                         return 1;
  45                 }
  46         }
  47 
  48         return 0;
  49 }
  50 
  51 int do_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, fd_set *res_rfds, fd_set *res_wfds, fd_set *res_efds)
  52 {
  53         int n, count;
  54         struct inode *i;
  55 
  56         count = 0;
  57         for(;;) {
  58                 for(n = 0; n < nfds; n++) {
  59                         if(!current->fd[n]) {
  60                                 continue;
  61                         }
  62                         i = fd_table[current->fd[n]].inode;
  63                         if(__FD_ISSET(n, rfds)) {
  64                                 if(do_check(i, SEL_R)) {
  65                                         __FD_SET(n, res_rfds);
  66                                         count++;
  67                                 }
  68                         }
  69                         if(__FD_ISSET(n, wfds)) {
  70                                 if(do_check(i, SEL_W)) {
  71                                         __FD_SET(n, res_wfds);
  72                                         count++;
  73                                 }
  74                         }
  75                         if(__FD_ISSET(n, efds)) {
  76                                 if(do_check(i, SEL_E)) {
  77                                         __FD_SET(n, res_efds);
  78                                         count++;
  79                                 }
  80                         }
  81                 }
  82 
  83                 if(count || !current->timeout || current->sigpending & ~current->sigblocked) {
  84                         break;
  85                 }
  86                 sleep(&do_select, PROC_INTERRUPTIBLE);
  87         }
  88 
  89         return count;
  90 }
  91 
  92 int sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
  93 {
  94         unsigned long int t;
  95         fd_set rfds, wfds, efds;
  96         fd_set res_rfds, res_wfds, res_efds;
  97         int errno;
  98 
  99 #ifdef __DEBUG__
 100         printk("(pid %d) sys_select(%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x [%d])\n", current->pid, nfds, (int)readfds, (int)writefds, (int)exceptfds, (int)timeout, (int)timeout ? tv2ticks(timeout): 0);
 101 #endif /*__DEBUG__ */
 102 
 103         if(nfds < 0) {
 104                 return -EINVAL;
 105         }
 106         if(nfds > MIN(__FD_SETSIZE, NR_OPENS)) {
 107                 nfds = MIN(__FD_SETSIZE, NR_OPENS);
 108         }
 109 
 110         if(readfds) {
 111                 if((errno = check_user_area(VERIFY_WRITE, readfds, sizeof(fd_set)))) {
 112                         return errno;
 113                 }
 114                 memcpy_b(&rfds, readfds, sizeof(fd_set));
 115         } else {
 116                 __FD_ZERO(&rfds);
 117         }
 118         if(writefds) {
 119                 if((errno = check_user_area(VERIFY_WRITE, writefds, sizeof(fd_set)))) {
 120                         return errno;
 121                 }
 122                 memcpy_b(&wfds, writefds, sizeof(fd_set));
 123         } else {
 124                 __FD_ZERO(&wfds);
 125         }
 126         if(exceptfds) {
 127                 if((errno = check_user_area(VERIFY_WRITE, exceptfds, sizeof(fd_set)))) {
 128                         return errno;
 129                 }
 130                 memcpy_b(&efds, exceptfds, sizeof(fd_set));
 131         } else {
 132                 __FD_ZERO(&efds);
 133         }
 134 
 135         /* check the validity of all fds */
 136         if((errno = check_fds(nfds, &rfds, &wfds, &efds)) < 0) {
 137                 return errno;
 138         }
 139 
 140         if(timeout) {
 141                 t = tv2ticks(timeout);
 142         } else {
 143                 t = INFINITE_WAIT;
 144         }
 145 
 146         __FD_ZERO(&res_rfds);
 147         __FD_ZERO(&res_wfds);
 148         __FD_ZERO(&res_efds);
 149 
 150         current->timeout = t;
 151         if((errno = do_select(nfds, &rfds, &wfds, &efds, &res_rfds, &res_wfds, &res_efds)) < 0) {
 152                 return errno;
 153         }
 154         current->timeout = 0;
 155 
 156         if(readfds) {
 157                 memcpy_b(readfds, &res_rfds, sizeof(fd_set));
 158         }
 159         if(writefds) {
 160                 memcpy_b(writefds, &res_wfds, sizeof(fd_set));
 161         }
 162         if(exceptfds) {
 163                 memcpy_b(exceptfds, &res_efds, sizeof(fd_set));
 164         }
 165         return errno;
 166 }

/* [previous][next][first][last][top][bottom][index][help] */