Date: Sat, 21 Oct 2000 09:09:56 -0700 (PDT) From: grubba@roxen.com To: freebsd-gnats-submit@FreeBSD.org Subject: misc/22190: A threaded read(2) from a socketpair(2) fd can sometimes fail with errno 19 (ENODEV) Message-ID: <20001021160956.9375F37B4C5@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 22190
>Category: misc
>Synopsis: A threaded read(2) from a socketpair(2) fd can sometimes fail with errno 19 (ENODEV)
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sat Oct 21 09:10:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: Henrik Grubbström
>Release: 4.0-RELEASE #0
>Organization:
Roxen Internet Software
>Environment:
FreeBSD snok.idonex.se 4.0-RELEASE FreeBSD 4.0-RELEASE #0: Wed Mar 15 02:16:55 GMT 2000 jkh@monster.cdrom.com:/usr/src/sys/compile/GENERIC i386
>Description:
In the testsuite for a threaded application, a process spawning test
that spawns 1000 /bin/cat /dev/null and waits for them sometimes fails
because read(2) returns -1 with errno set to 19 (ENODEV). ENODEV is
not a documented error code for read(2).
Down-stripped code that triggs the bug:
{
pid_t pid=-2;
int control_pipe[2]; /* Used for communication with the child. */
char buf[4];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, control_pipe) < 0) {
error("Failed to create child communication pipe.\n");
}
{
int loop_cnt = 0;
sigset_t new_sig, old_sig;
sigfillset(&new_sig);
while(sigprocmask(SIG_BLOCK, &new_sig, &old_sig))
;
do {
pid=fork();
if (pid == -1) {
if (errno == EAGAIN) {
/* Process table full or similar.
* Try sleeping for a bit.
*/
if (loop_cnt++ < 60) {
/* Don't sleep for too long... */
poll(NULL, 0, 100);
/* Try again */
continue;
}
} else if (errno == EINTR) {
/* Try again */
continue;
}
}
break;
} while(1);
while(sigprocmask(SIG_SETMASK, &old_sig, 0))
;
}
if(pid == -1) {
int e = errno;
/*
* fork() failed
*/
while(close(control_pipe[0]) < 0 && errno==EINTR);
while(close(control_pipe[1]) < 0 && errno==EINTR);
error("Process.create_process(): fork() failed. errno:%d\n",
e);
} else if(pid) {
int olderrno;
/*
* The parent process
*/
/* Close our child's end of the pipe. */
while(close(control_pipe[1]) < 0 && errno==EINTR);
/* Wake up the child. */
buf[0] = 0;
while (((e = write(control_pipe[0], buf, 1)) < 0) && (errno == EINTR))
;
if(e!=1) {
/* Paranoia in case close() sets errno. */
olderrno = errno;
while(close(control_pipe[0]) < 0 && errno==EINTR)
;
error("Child process died prematurely. (e=%d errno=%d)\n",
e, olderrno);
}
/* Wait for exec or error */
while (((e = read(control_pipe[0], buf, 3)) < 0) && (errno == EINTR))
;
/* Paranoia in case close() sets errno. */
olderrno = errno;
while(close(control_pipe[0]) < 0 && errno==EINTR)
;
if (!e) {
/* OK! */
pop_n_elems(args);
push_int(0);
return;
} else {
/* Something went wrong. */
switch(buf[0]) {
/* ... */
case 0:
/* read() probably failed. */
default:
/******************************************************************
* This point is reached with buf = {0, 4, 0}, e = -1, olderrno=19.
*****************************************************************/
error("Process.create_process(): "
"Child failed: %d, %d, %d, %d, %d!\n",
buf[0], buf[1], buf[2], e, olderrno);
break;
}
}
}else{
/*
* The child process
*/
/* Close our parent's end of the pipe. */
while(close(control_pipe[0]) < 0 && errno==EINTR);
/* Ensure that the pipe will be closed when the child starts. */
if(set_close_on_exec(control_pipe[1], 1) < 0)
PROCERROR(PROCE_CLOEXEC, 0);
/* Wait for parent to get ready... */
while ((( e = read(control_pipe[1], buf, 1)) < 0) && (errno == EINTR))
;
/* ... */
execvp(argv[0], argv);
PROCERROR(PROCE_EXEC, 0);
exit(99);
}
}
For the full source, please check src/signal_handler.c:f_create_process() in a Pike distribution.
Testsuite report:
testsuite: Test 9406 (shift 0) (CRNL) failed.
1: mixed a() { for(int x=0;x<10;x++) { for(int e=0;e<100;e++) if(Process.create_process(({"/bin/cat","/dev/null"}))->wait()) return e; __signal_watchdog(); } return -1;; }
2: mixed b() { return -1; }
Error: Process.create_process(): Child failed: 0, 4, 0, -1, 19!
__builtin.create_process: create(({"/bin/cat","/dev/null"}))
__builtin: create_process()
testsuite: Test 9406 (shift 0) (CRNL):1: a()
/tmp/autobuild/pike7.1-20001021082826.tar/bin/test_pike.pike:572: main(3,({"/tmp/autobuild/pike7.1-20001021082826.tar/bin/test_pike.pike","modules/CommonLog/module_testsuite","modules/Gdbm/module_testsuite","modules/Gettext/module_testsuite","modules/Gmp/module_testsuite",,,34}))
>How-To-Repeat:
Unfortunately, the problem is intermittent.
It may be triggered by resource exhaustion.
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001021160956.9375F37B4C5>
