@@ -983,6 +983,7 @@ int main(int argc, char **argv)
983983 size_t data_passed [3 ];
984984 size_t total_data ;
985985 char str [256 ];
986+ int sync_pipefd [3 ][2 ];
986987
987988 struct itimerval itimer ;
988989 struct sigaction sigact ;
@@ -1167,6 +1168,13 @@ int main(int argc, char **argv)
11671168 if ( pipe (child_pipefd [i ])!= 0 ) error (errno ,"creating pipe for fd %d" ,i );
11681169 }
11691170
1171+ /* Setup pipes for notifying parent and child before starting timers.
1172+ sync_pipefd[1] is used for parent->child notification (parent closes its PIPE_IN to signal).
1173+ sync_pipefd[2] is used for child->parent notification (child closes its PIPE_IN to signal). */
1174+ for (i = 1 ; i <=2 ; i ++ ) {
1175+ if ( pipe2 (sync_pipefd [i ], O_CLOEXEC )!= 0 ) error (errno ,"creating sync pipe" );
1176+ }
1177+
11701178 if ( sigemptyset (& emptymask )!= 0 ) error (errno ,"creating empty signal mask" );
11711179
11721180 /* unmask all signals, except SIGCHLD: detected in pselect() below */
@@ -1261,8 +1269,19 @@ int main(int argc, char **argv)
12611269 error (errno ,"closing pipe for fd %d" ,i );
12621270 }
12631271 }
1272+ if ( close (sync_pipefd [1 ][PIPE_IN ])!= 0 || close (sync_pipefd [2 ][PIPE_OUT ])!= 0 ) {
1273+ error (errno ,"closing pipe for sync_pipefd" );
1274+ }
12641275 verbose ("pipes closed in child" );
12651276
1277+ /* block until parent is ready (sync_pipefd[1][PIPE_OUT] closes).
1278+ If we read() and get 0 bytes, we know that parent has closed sync_pipefd[1][PIPE_IN].
1279+ And it would be unexpected if we get data from the parent before it (show an error). */
1280+ if ( read (sync_pipefd [1 ][PIPE_OUT ], NULL , 0 ) != 0 ) {
1281+ error (errno , "unexpected sync_pipefd read error in child" );
1282+ }
1283+ /* We don't need to explicitly close sync_pipefd[2]: it will atomically be closed on execve(). */
1284+
12661285 /* And execute child command. */
12671286 execvp (cmdname ,cmdargs );
12681287 error (errno ,"cannot start `%s'" ,cmdname );
@@ -1277,14 +1296,15 @@ int main(int argc, char **argv)
12771296 verbose ("watchdog using user ID `%d'" ,getuid ());
12781297 }
12791298
1280- if ( gettimeofday (& starttime ,NULL ) ) error (errno ,"getting time" );
1281-
12821299 /* Close unused file descriptors */
12831300 for (i = 1 ; i <=2 ; i ++ ) {
12841301 if ( close (child_pipefd [i ][PIPE_IN ])!= 0 ) {
12851302 error (errno ,"closing pipe for fd %i" ,i );
12861303 }
12871304 }
1305+ if ( close (sync_pipefd [1 ][PIPE_OUT ])!= 0 || close (sync_pipefd [2 ][PIPE_IN ])!= 0 ) {
1306+ error (errno ,"closing pipe for sync_pipefd" );
1307+ }
12881308
12891309 /* Redirect child stdout/stderr to file */
12901310 for (i = 1 ; i <=2 ; i ++ ) {
@@ -1341,6 +1361,17 @@ int main(int argc, char **argv)
13411361 verbose ("setting hard wall-time limit to %.3f seconds" ,walltimelimit [1 ]);
13421362 }
13431363
1364+ /* Close PIPE_IN of sync_pipefd[1]: allow child to execve() */
1365+ if ( close (sync_pipefd [1 ][PIPE_IN ])!= 0 ) {
1366+ error (errno ,"closing pipe for sync_pipefd[1] (IN)" );
1367+ }
1368+ /* Wait before starting timers. Use read() like what is done in child */
1369+ if ( read (sync_pipefd [2 ][PIPE_OUT ], NULL , 0 ) != 0 ) {
1370+ error (errno , "unexpected sync_pipefd read error in parent" );
1371+ }
1372+
1373+ if ( gettimeofday (& starttime ,NULL ) ) error (errno ,"getting time" );
1374+
13441375 if ( times (& startticks )== (clock_t ) - 1 ) {
13451376 error (errno ,"getting start clock ticks" );
13461377 }
0 commit comments