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