Date: Tue, 19 Dec 2000 20:40:24 -0800 (PST) From: andy@silverbrook.com.au To: freebsd-gnats-submit@FreeBSD.org Subject: misc/23679: libc_r thread scheduling sleep time mis-calculations Message-ID: <200012200440.eBK4eOq41601@freefall.freebsd.org> Resent-Message-ID: <200012200450.eBK4o1a42686@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 23679 >Category: misc >Synopsis: libc_r thread scheduling sleep time mis-calculations >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Dec 19 20:50:00 PST 2000 >Closed-Date: >Last-Modified: >Originator: Andy Newman >Release: RELENG_4 >Organization: Silverbrook Research >Environment: FreeBSD bebop.silverbrook.com.au 4.2-STABLE FreeBSD 4.2-STABLE #0: Wed Nov 22 08:52:41 EST 2000 toor@bebop.silverbrook.com.au:/usr/obj/usr/src/sys/bebop i386 >Description: In a particular circumstance libc_r mis-calculates sleep times. The attached demonstration program shows the problem. A number of child processes are forked from a parent and then attempt to acquire a (SysV IPC) semaphore, do some work (sleep) and release the semaphore. Each child process attempts to sleep for a constant time (1 second). Building against libc produces the expected results. Building against libc_r produces differences in sleep times. The first child process sleeps for the correct time, the second for twice as long, the third for twice as long as that etc.... (powers of 2). Tracing the system calls being made shows that incorrect timeout values are being passed to poll(2) presumably via libc_r's thread scheduler. Prior to the poll(2) calls there are two gettimeofday(2) calls which is consistent with an execution path from libc_r's nanosleep() routine through to the thread scheduler. The shar achive has a test, tst.c, and a makefile. Two executables are built, tst, linked against libc, and tstp, linked against libc_r. The program is invoked with a single arg, the semaphore's "key". The program creates a sempahore and forks 8 child processes which all try to acquire it, do some work and release it. >How-To-Repeat: # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # tst.c # Makefile # echo x - tst.c sed 's/^X//' >tst.c << 'END-of-tst.c' X/* X * Demonstrate problems with process sleep times. X */ X X#include <stdio.h> X#include <stdarg.h> X#include <sys/types.h> X#include <sys/time.h> X#include <sys/ipc.h> X#include <sys/sem.h> X#include <sys/wait.h> X#include <unistd.h> X#include <err.h> X#include <time.h> X Xint mypid; X Xvoid child(int); Xvoid release(int, const char *); Xvoid log(const char *, ...); X Xint Xmain(int argc, char **argv) X{ X int semid; X int i; X key_t key; X unsigned int n_proc = 8; X unsigned long ulvar; X X mypid = getpid(); X X if (argc < 2) X goto usage; X if (sscanf(argv[1], "%lu", &ulvar) != 1) X goto usage; X key = (key_t)ulvar; X if (argc > 2 && sscanf(argv[2], "%u", &n_proc) != 1) X goto usage; X X if ((semid = semget(key, 1, IPC_CREAT|0600)) == -1) X err(1, "semget(create)"); X if (semctl(semid, 0, SETVAL, 0) < 0) X err(1, "semctl(SETVAL)"); X log("parent created semaphore, id = 0x%08x", semid); X X for (i = 0; i < n_proc; ++i) X child(semid); X X log("parent releasing semaphore"); X release(semid, "parent"); X X while (i-- > 0) X { X int status; X pid_t pid; X pid = wait(&status); X log("parent reaped child pid=%d, status=%0o", (int)pid, status); X } X X semctl(semid, 0, IPC_RMID, 0); X X return 0; X Xusage: X fprintf(stderr, "usage: %s semaphore-key [num_children]\n", argv[0]); X return 1; X} X Xvoid Xlog(const char *fmt, ...) X{ X va_list va; X struct timeval tv; X char buf[1024]; X X gettimeofday(&tv, NULL); X sprintf(buf, "%lu.%-6lu: ", tv.tv_sec, tv.tv_usec); X va_start(va, fmt); X vsprintf(buf+strlen(buf), fmt, va); X va_end(va); X fprintf(stderr, "%s\n", buf); X fflush(stderr); X} X Xvoid Xacquire(int semid) X{ X struct sembuf semops; X X semops.sem_num = 0; X semops.sem_op = -1; X semops.sem_flg = 0; X X log("child %d acquiring semaphore", mypid); X if (semop(semid, &semops, 1) < 0) X err(1, "acquire"); X log("child %d acquired semaphore", mypid); X} X Xvoid Xrelease(int semid, const char *who) X{ X struct sembuf semops; X X semops.sem_num = 0; X semops.sem_op = 1; X semops.sem_flg = 0; X log("%s %d releasing semaphore", who, mypid); X if (semop(semid, &semops, 1) < 0) X err(1, "release"); X log("%s %d released semaphore", who, mypid); X} X Xvoid Xwork(void) X{ X time_t t1, t2; X X log("child %d working for 1 second", mypid); X t1 = time(NULL); X sleep(1); X t2 = time(NULL); X log("child %d done working: %d elapsed", mypid, t2 - t1); X} X Xvoid Xchild(int semid) X{ X switch (fork()) X { X case -1: X err(1, "fork"); X X case 0: X mypid = getpid(); X acquire(semid); X work(); X release(semid, "child"); X log("child %d done", mypid); X _exit(0); X } X} END-of-tst.c echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' Xall: tst tstp X Xtst : tst.c X cc -g -Wall -o tst tst.c X Xtstp: tst.c X cc -g -Wall -o tstp -pthread tst.c X Xclean: X rm -f tst tstp ktrace.out END-of-Makefile exit >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?200012200440.eBK4eOq41601>