1 /*
2 **  GNU Pth - The GNU Portable Threads
3 **  Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com>
4 **
5 **  This file is part of GNU Pth, a non-preemptive thread scheduling
6 **  library which can be found at http://www.gnu.org/software/pth/.
7 **
8 **  This library is free software; you can redistribute it and/or
9 **  modify it under the terms of the GNU Lesser General Public
10 **  License as published by the Free Software Foundation; either
11 **  version 2.1 of the License, or (at your option) any later version.
12 **
13 **  This library is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 **  Lesser General Public License for more details.
17 **
18 **  You should have received a copy of the GNU Lesser General Public
19 **  License along with this library; if not, write to the Free Software
20 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 **  USA, or contact Ralf S. Engelschall <rse@engelschall.com>.
22 **
23 **  pth_util.c: Pth utility functions
24 */
25                              /* ``Premature optimization is
26                                   the root of all evil.''
27                                              -- D.E.Knuth */
28 #include "pth_p.h"
29 
30 /* calculate numerical mimimum */
31 #if cpp
32 #define pth_util_min(a,b) \
33         ((a) > (b) ? (b) : (a))
34 #endif
35 
36 /* delete a pending signal */
pth_util_sigdelete_sighandler(int _sig)37 static void pth_util_sigdelete_sighandler(int _sig)
38 {
39     /* nop */
40     return;
41 }
pth_util_sigdelete(int sig)42 intern int pth_util_sigdelete(int sig)
43 {
44     sigset_t ss, oss;
45     struct sigaction sa, osa;
46 
47     /* check status of signal */
48     sigpending(&ss);
49     if (!sigismember(&ss, sig))
50         return FALSE;
51 
52     /* block signal and remember old mask */
53     sigemptyset(&ss);
54     sigaddset(&ss, sig);
55     pth_sc(sigprocmask)(SIG_BLOCK, &ss, &oss);
56 
57     /* set signal action to our dummy handler */
58     sa.sa_handler = pth_util_sigdelete_sighandler;
59     sigfillset(&sa.sa_mask);
60     sa.sa_flags = 0;
61     if (sigaction(sig, &sa, &osa) != 0) {
62         pth_sc(sigprocmask)(SIG_SETMASK, &oss, NULL);
63         return FALSE;
64     }
65 
66     /* now let signal be delivered */
67     sigfillset(&ss);
68     sigdelset(&ss, sig);
69     sigsuspend(&ss);
70 
71     /* restore signal mask and handler */
72     sigaction(sig, &osa, NULL);
73     pth_sc(sigprocmask)(SIG_SETMASK, &oss, NULL);
74     return TRUE;
75 }
76 
77 /* copy a string like strncpy() but always null-terminate */
pth_util_cpystrn(char * dst,const char * src,size_t dst_size)78 intern char *pth_util_cpystrn(char *dst, const char *src, size_t dst_size)
79 {
80     register char *d, *end;
81 
82     if (dst_size == 0)
83         return dst;
84     d = dst;
85     end = dst + dst_size - 1;
86     for (; d < end; ++d, ++src) {
87         if ((*d = *src) == '\0')
88             return d;
89     }
90     *d = '\0';
91     return d;
92 }
93 
94 /* check whether a file-descriptor is valid */
pth_util_fd_valid(int fd)95 intern int pth_util_fd_valid(int fd)
96 {
97     if (fd < 0 || fd >= FD_SETSIZE)
98         return FALSE;
99     if (fcntl(fd, F_GETFL) == -1 && errno == EBADF)
100         return FALSE;
101     return TRUE;
102 }
103 
104 /* merge input fd set into output fds */
pth_util_fds_merge(int nfd,fd_set * ifds1,fd_set * ofds1,fd_set * ifds2,fd_set * ofds2,fd_set * ifds3,fd_set * ofds3)105 intern void pth_util_fds_merge(int nfd,
106                                fd_set *ifds1, fd_set *ofds1,
107                                fd_set *ifds2, fd_set *ofds2,
108                                fd_set *ifds3, fd_set *ofds3)
109 {
110     register int s;
111 
112     for (s = 0; s < nfd; s++) {
113         if (ifds1 != NULL)
114             if (FD_ISSET(s, ifds1))
115                 FD_SET(s, ofds1);
116         if (ifds2 != NULL)
117             if (FD_ISSET(s, ifds2))
118                 FD_SET(s, ofds2);
119         if (ifds3 != NULL)
120             if (FD_ISSET(s, ifds3))
121                 FD_SET(s, ofds3);
122     }
123     return;
124 }
125 
126 /* test whether fds in the input fd sets occurred in the output fds */
pth_util_fds_test(int nfd,fd_set * ifds1,fd_set * ofds1,fd_set * ifds2,fd_set * ofds2,fd_set * ifds3,fd_set * ofds3)127 intern int pth_util_fds_test(int nfd,
128                              fd_set *ifds1, fd_set *ofds1,
129                              fd_set *ifds2, fd_set *ofds2,
130                              fd_set *ifds3, fd_set *ofds3)
131 {
132     register int s;
133 
134     for (s = 0; s < nfd; s++) {
135         if (ifds1 != NULL)
136             if (FD_ISSET(s, ifds1) && FD_ISSET(s, ofds1))
137                 return TRUE;
138         if (ifds2 != NULL)
139             if (FD_ISSET(s, ifds2) && FD_ISSET(s, ofds2))
140                 return TRUE;
141         if (ifds3 != NULL)
142             if (FD_ISSET(s, ifds3) && FD_ISSET(s, ofds3))
143                 return TRUE;
144     }
145     return FALSE;
146 }
147 
148 /*
149  * clear fds in input fd sets if not occurred in output fd sets and return
150  * number of remaining input fds. This number uses BSD select(2) semantics: a
151  * fd in two set counts twice!
152  */
pth_util_fds_select(int nfd,fd_set * ifds1,fd_set * ofds1,fd_set * ifds2,fd_set * ofds2,fd_set * ifds3,fd_set * ofds3)153 intern int pth_util_fds_select(int nfd,
154                                fd_set *ifds1, fd_set *ofds1,
155                                fd_set *ifds2, fd_set *ofds2,
156                                fd_set *ifds3, fd_set *ofds3)
157 {
158     register int s;
159     register int n;
160 
161     n = 0;
162     for (s = 0; s < nfd; s++) {
163         if (ifds1 != NULL && FD_ISSET(s, ifds1)) {
164             if (!FD_ISSET(s, ofds1))
165                FD_CLR(s, ifds1);
166             else
167                n++;
168         }
169         if (ifds2 != NULL && FD_ISSET(s, ifds2)) {
170             if (!FD_ISSET(s, ofds2))
171                 FD_CLR(s, ifds2);
172             else
173                 n++;
174         }
175         if (ifds3 != NULL && FD_ISSET(s, ifds3)) {
176             if (!FD_ISSET(s, ofds3))
177                 FD_CLR(s, ifds3);
178             else
179                 n++;
180         }
181     }
182     return n;
183 }
184 
185