Imported Upstream version 4.3
[platform/upstream/make.git] / src / posixos.c
1 /* POSIX-based operating system interface for GNU Make.
2 Copyright (C) 2016-2020 Free Software Foundation, Inc.
3 This file is part of GNU Make.
4
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
8 version.
9
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include "makeint.h"
18
19 #include <stdio.h>
20
21 #ifdef HAVE_FCNTL_H
22 # include <fcntl.h>
23 #elif defined(HAVE_SYS_FILE_H)
24 # include <sys/file.h>
25 #endif
26
27 #if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H)
28 # include <sys/select.h>
29 #endif
30
31 #include "debug.h"
32 #include "job.h"
33 #include "os.h"
34
35 #ifdef MAKE_JOBSERVER
36
37 /* This section provides OS-specific functions to support the jobserver.  */
38
39 /* These track the state of the jobserver pipe.  Passed to child instances.  */
40 static int job_fds[2] = { -1, -1 };
41
42 /* Used to signal read() that a SIGCHLD happened.  Always CLOEXEC.
43    If we use pselect() this will never be created and always -1.
44  */
45 static int job_rfd = -1;
46
47 /* Token written to the pipe (could be any character...)  */
48 static char token = '+';
49
50 static int
51 make_job_rfd (void)
52 {
53 #ifdef HAVE_PSELECT
54   /* Pretend we succeeded.  */
55   return 0;
56 #else
57   EINTRLOOP (job_rfd, dup (job_fds[0]));
58   if (job_rfd >= 0)
59     fd_noinherit (job_rfd);
60
61   return job_rfd;
62 #endif
63 }
64
65 static void
66 set_blocking (int fd, int blocking)
67 {
68   /* If we're not using pselect() don't change the blocking.  */
69 #ifdef HAVE_PSELECT
70   int flags;
71   EINTRLOOP (flags, fcntl (fd, F_GETFL));
72   if (flags >= 0)
73     {
74       int r;
75       flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
76       EINTRLOOP (r, fcntl (fd, F_SETFL, flags));
77       if (r < 0)
78         pfatal_with_name ("fcntl(O_NONBLOCK)");
79     }
80 #endif
81 }
82
83 unsigned int
84 jobserver_setup (int slots)
85 {
86   int r;
87
88   EINTRLOOP (r, pipe (job_fds));
89   if (r < 0)
90     pfatal_with_name (_("creating jobs pipe"));
91
92   /* By default we don't send the job pipe FDs to our children.
93      See jobserver_pre_child() and jobserver_post_child().  */
94   fd_noinherit (job_fds[0]);
95   fd_noinherit (job_fds[1]);
96
97   if (make_job_rfd () < 0)
98     pfatal_with_name (_("duping jobs pipe"));
99
100   while (slots--)
101     {
102       EINTRLOOP (r, write (job_fds[1], &token, 1));
103       if (r != 1)
104         pfatal_with_name (_("init jobserver pipe"));
105     }
106
107   /* When using pselect() we want the read to be non-blocking.  */
108   set_blocking (job_fds[0], 0);
109
110   return 1;
111 }
112
113 unsigned int
114 jobserver_parse_auth (const char *auth)
115 {
116   /* Given the command-line parameter, parse it.  */
117   if (sscanf (auth, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
118     OS (fatal, NILF,
119         _("internal error: invalid --jobserver-auth string '%s'"), auth);
120
121   DB (DB_JOBS,
122       (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1]));
123
124 #ifdef HAVE_FCNTL_H
125 # define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1)
126 #else
127 # define FD_OK(_f) 1
128 #endif
129
130   /* Make sure our pipeline is valid, and (possibly) create a duplicate pipe,
131      that will be closed in the SIGCHLD handler.  If this fails with EBADF,
132      the parent has closed the pipe on us because it didn't think we were a
133      submake.  If so, warn and default to -j1.  */
134
135   if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1]) || make_job_rfd () < 0)
136     {
137       if (errno != EBADF)
138         pfatal_with_name (_("jobserver pipeline"));
139
140       job_fds[0] = job_fds[1] = -1;
141
142       return 0;
143     }
144
145   /* When using pselect() we want the read to be non-blocking.  */
146   set_blocking (job_fds[0], 0);
147
148   return 1;
149 }
150
151 char *
152 jobserver_get_auth (void)
153 {
154   char *auth = xmalloc ((INTSTR_LENGTH * 2) + 2);
155   sprintf (auth, "%d,%d", job_fds[0], job_fds[1]);
156   return auth;
157 }
158
159 unsigned int
160 jobserver_enabled (void)
161 {
162   return job_fds[0] >= 0;
163 }
164
165 void
166 jobserver_clear (void)
167 {
168   if (job_fds[0] >= 0)
169     close (job_fds[0]);
170   if (job_fds[1] >= 0)
171     close (job_fds[1]);
172   if (job_rfd >= 0)
173     close (job_rfd);
174
175   job_fds[0] = job_fds[1] = job_rfd = -1;
176 }
177
178 void
179 jobserver_release (int is_fatal)
180 {
181   int r;
182   EINTRLOOP (r, write (job_fds[1], &token, 1));
183   if (r != 1)
184     {
185       if (is_fatal)
186         pfatal_with_name (_("write jobserver"));
187       perror_with_name ("write", "");
188     }
189 }
190
191 unsigned int
192 jobserver_acquire_all (void)
193 {
194   unsigned int tokens = 0;
195
196   /* Use blocking reads to wait for all outstanding jobs.  */
197   set_blocking (job_fds[0], 1);
198
199   /* Close the write side, so the read() won't hang forever.  */
200   close (job_fds[1]);
201   job_fds[1] = -1;
202
203   while (1)
204     {
205       char intake;
206       int r;
207       EINTRLOOP (r, read (job_fds[0], &intake, 1));
208       if (r != 1)
209         return tokens;
210       ++tokens;
211     }
212 }
213
214 /* Prepare the jobserver to start a child process.  */
215 void
216 jobserver_pre_child (int recursive)
217 {
218   if (recursive && job_fds[0] >= 0)
219     {
220       fd_inherit (job_fds[0]);
221       fd_inherit (job_fds[1]);
222     }
223 }
224
225 /* Reconfigure the jobserver after starting a child process.  */
226 void
227 jobserver_post_child (int recursive)
228 {
229   if (recursive && job_fds[0] >= 0)
230     {
231       fd_noinherit (job_fds[0]);
232       fd_noinherit (job_fds[1]);
233     }
234 }
235
236 void
237 jobserver_signal (void)
238 {
239   if (job_rfd >= 0)
240     {
241       close (job_rfd);
242       job_rfd = -1;
243     }
244 }
245
246 void
247 jobserver_pre_acquire (void)
248 {
249   /* Make sure we have a dup'd FD.  */
250   if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0)
251     pfatal_with_name (_("duping jobs pipe"));
252 }
253
254 #ifdef HAVE_PSELECT
255
256 /* Use pselect() to atomically wait for both a signal and a file descriptor.
257    It also provides a timeout facility so we don't need to use SIGALRM.
258
259    This method relies on the fact that SIGCHLD will be blocked everywhere,
260    and only unblocked (atomically) within the pselect() call, so we can
261    never miss a SIGCHLD.
262  */
263 unsigned int
264 jobserver_acquire (int timeout)
265 {
266   struct timespec spec;
267   struct timespec *specp = NULL;
268   sigset_t empty;
269
270   sigemptyset (&empty);
271
272   if (timeout)
273     {
274       /* Alarm after one second (is this too granular?)  */
275       spec.tv_sec = 1;
276       spec.tv_nsec = 0;
277       specp = &spec;
278     }
279
280   while (1)
281     {
282       fd_set readfds;
283       int r;
284       char intake;
285
286       FD_ZERO (&readfds);
287       FD_SET (job_fds[0], &readfds);
288
289       r = pselect (job_fds[0]+1, &readfds, NULL, NULL, specp, &empty);
290       if (r < 0)
291         switch (errno)
292           {
293           case EINTR:
294             /* SIGCHLD will show up as an EINTR.  */
295             return 0;
296
297           case EBADF:
298             /* Someone closed the jobs pipe.
299                That shouldn't happen but if it does we're done.  */
300               O (fatal, NILF, _("job server shut down"));
301
302           default:
303             pfatal_with_name (_("pselect jobs pipe"));
304           }
305
306       if (r == 0)
307         /* Timeout.  */
308         return 0;
309
310       /* The read FD is ready: read it!  This is non-blocking.  */
311       EINTRLOOP (r, read (job_fds[0], &intake, 1));
312
313       if (r < 0)
314         {
315           /* Someone sniped our token!  Try again.  */
316           if (errno == EAGAIN)
317             continue;
318
319           pfatal_with_name (_("read jobs pipe"));
320         }
321
322       /* read() should never return 0: only the master make can reap all the
323          tokens and close the write side...??  */
324       return r > 0;
325     }
326 }
327
328 #else
329
330 /* This method uses a "traditional" UNIX model for waiting on both a signal
331    and a file descriptor.  However, it's complex and since we have a SIGCHLD
332    handler installed we need to check ALL system calls for EINTR: painful!
333
334    Read a token.  As long as there's no token available we'll block.  We
335    enable interruptible system calls before the read(2) so that if we get a
336    SIGCHLD while we're waiting, we'll return with EINTR and we can process the
337    death(s) and return tokens to the free pool.
338
339    Once we return from the read, we immediately reinstate restartable system
340    calls.  This allows us to not worry about checking for EINTR on all the
341    other system calls in the program.
342
343    There is one other twist: there is a span between the time reap_children()
344    does its last check for dead children and the time the read(2) call is
345    entered, below, where if a child dies we won't notice.  This is extremely
346    serious as it could cause us to deadlock, given the right set of events.
347
348    To avoid this, we do the following: before we reap_children(), we dup(2)
349    the read FD on the jobserver pipe.  The read(2) call below uses that new
350    FD.  In the signal handler, we close that FD.  That way, if a child dies
351    during the section mentioned above, the read(2) will be invoked with an
352    invalid FD and will return immediately with EBADF.  */
353
354 static RETSIGTYPE
355 job_noop (int sig UNUSED)
356 {
357 }
358
359 /* Set the child handler action flags to FLAGS.  */
360 static void
361 set_child_handler_action_flags (int set_handler, int set_alarm)
362 {
363   struct sigaction sa;
364
365 #ifdef __EMX__
366   /* The child handler must be turned off here.  */
367   signal (SIGCHLD, SIG_DFL);
368 #endif
369
370   memset (&sa, '\0', sizeof sa);
371   sa.sa_handler = child_handler;
372   sa.sa_flags = set_handler ? 0 : SA_RESTART;
373
374 #if defined SIGCHLD
375   if (sigaction (SIGCHLD, &sa, NULL) < 0)
376     pfatal_with_name ("sigaction: SIGCHLD");
377 #endif
378
379 #if defined SIGCLD && SIGCLD != SIGCHLD
380   if (sigaction (SIGCLD, &sa, NULL) < 0)
381     pfatal_with_name ("sigaction: SIGCLD");
382 #endif
383
384 #if defined SIGALRM
385   if (set_alarm)
386     {
387       /* If we're about to enter the read(), set an alarm to wake up in a
388          second so we can check if the load has dropped and we can start more
389          work.  On the way out, turn off the alarm and set SIG_DFL.  */
390       if (set_handler)
391         {
392           sa.sa_handler = job_noop;
393           sa.sa_flags = 0;
394           if (sigaction (SIGALRM, &sa, NULL) < 0)
395             pfatal_with_name ("sigaction: SIGALRM");
396           alarm (1);
397         }
398       else
399         {
400           alarm (0);
401           sa.sa_handler = SIG_DFL;
402           sa.sa_flags = 0;
403           if (sigaction (SIGALRM, &sa, NULL) < 0)
404             pfatal_with_name ("sigaction: SIGALRM");
405         }
406     }
407 #endif
408 }
409
410 unsigned int
411 jobserver_acquire (int timeout)
412 {
413   char intake;
414   int got_token;
415   int saved_errno;
416
417   /* Set interruptible system calls, and read() for a job token.  */
418   set_child_handler_action_flags (1, timeout);
419
420   EINTRLOOP (got_token, read (job_rfd, &intake, 1));
421   saved_errno = errno;
422
423   set_child_handler_action_flags (0, timeout);
424
425   if (got_token == 1)
426     return 1;
427
428   /* If the error _wasn't_ expected (EINTR or EBADF), fatal.  Otherwise,
429      go back and reap_children(), and try again.  */
430   errno = saved_errno;
431
432   if (errno != EINTR && errno != EBADF)
433     pfatal_with_name (_("read jobs pipe"));
434
435   if (errno == EBADF)
436     DB (DB_JOBS, ("Read returned EBADF.\n"));
437
438   return 0;
439 }
440
441 #endif /* HAVE_PSELECT */
442
443 #endif /* MAKE_JOBSERVER */
444
445 /* Create a "bad" file descriptor for stdin when parallel jobs are run.  */
446 int
447 get_bad_stdin (void)
448 {
449   static int bad_stdin = -1;
450
451   /* Set up a bad standard input that reads from a broken pipe.  */
452
453   if (bad_stdin == -1)
454     {
455       /* Make a file descriptor that is the read end of a broken pipe.
456          This will be used for some children's standard inputs.  */
457       int pd[2];
458       if (pipe (pd) == 0)
459         {
460           /* Close the write side.  */
461           (void) close (pd[1]);
462           /* Save the read side.  */
463           bad_stdin = pd[0];
464
465           /* Set the descriptor to close on exec, so it does not litter any
466              child's descriptor table.  When it is dup2'd onto descriptor 0,
467              that descriptor will not close on exec.  */
468           fd_noinherit (bad_stdin);
469         }
470     }
471
472   return bad_stdin;
473 }
474
475 /* Set file descriptors to be inherited / not inherited by subprocesses.  */
476
477 #if !defined(F_SETFD) || !defined(F_GETFD)
478 void fd_inherit (int fd) {}
479 void fd_noinherit (int fd) {}
480
481 #else
482
483 # ifndef FD_CLOEXEC
484 #  define FD_CLOEXEC 1
485 # endif
486
487 void
488 fd_inherit (int fd)
489 {
490   int flags;
491   EINTRLOOP (flags, fcntl (fd, F_GETFD));
492   if (flags >= 0)
493     {
494       int r;
495       flags &= ~FD_CLOEXEC;
496       EINTRLOOP (r, fcntl (fd, F_SETFD, flags));
497     }
498 }
499
500 void
501 fd_noinherit (int fd)
502 {
503     int flags;
504     EINTRLOOP(flags, fcntl(fd, F_GETFD));
505     if (flags >= 0)
506       {
507         int r;
508         flags |= FD_CLOEXEC;
509         EINTRLOOP(r, fcntl(fd, F_SETFD, flags));
510       }
511 }
512 #endif