From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/413 Path: news.gmane.org!not-for-mail From: =?UTF-8?B?THVrYSBNYXLEjWV0acSH?= Newsgroups: gmane.linux.lib.musl.general Subject: cluts daily reports 8/13 - pthread_eintr expanded Date: Sat, 13 Aug 2011 21:10:05 +0200 Message-ID: <4E46CC0D.4040601@gmail.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------010500050108060907070909" X-Trace: dough.gmane.org 1313262765 30309 80.91.229.12 (13 Aug 2011 19:12:45 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Sat, 13 Aug 2011 19:12:45 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-414-gllmg-musl=m.gmane.org@lists.openwall.com Sat Aug 13 21:12:42 2011 Return-path: Envelope-to: gllmg-musl@lo.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by lo.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1QsJdM-0000Ms-SW for gllmg-musl@lo.gmane.org; Sat, 13 Aug 2011 21:12:37 +0200 Original-Received: (qmail 27784 invoked by uid 550); 13 Aug 2011 19:12:36 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 27773 invoked from network); 13 Aug 2011 19:12:36 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=mWRyh4PPNyJygoAmEX9LuZWjLXeLQCQuFJsDWQuf5/0=; b=CEycGtsG39LF6YauOJLXZcGF/wQRxEaBqf+BUUWZmnk6gQyNKPpMrDHfiMVow621Jm /EtDwrkdmHkUF1iiZQ/O65VcaEMlNAymK09imNpxcPeOYHk7DAw294fyu3Ct+R+Mvm8J OjC4U1xQRUQJRne718a42EdTXlyV1+kSOx6Fs= User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110626 Icedove/3.1.11 Xref: news.gmane.org gmane.linux.lib.musl.general:413 Archived-At: This is a multi-part message in MIME format. --------------010500050108060907070909 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Done: *a lot more work done on pthread_eintr (if you need me to explain any of the unfinished code, tell me) Priorities: *pthread_eintr needs work (if someone's proficient with valgrind, I would appreciate help interpreting the output) *... `to-report` may be uninformative (.git gets in the way), but updated pthread_eintr is attached. P.S. I was offline for a while, and may be in the future. --------------010500050108060907070909 Content-Type: text/x-csrc; name="pthread_eintr.c" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="pthread_eintr.c" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/common.h" #include /* * Copyright (c) 2011 Luka Marčetić * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. */ /** ** \file ** Tests that EINTR isn't returned by interrupted pthread_* functions for which ** this is a specified behavior ** tests: pthread_create, ** depends: open,pipe,close, mmap, sigaction, kill,waitpid,nanosleep, fprintf, ** pause, pthread_cleanup_push, pthread_cleanup_pop, setjmp,longjmp ** sched_getscheduler,sched_get_priority_min,pthread_setschedprio, ** pthread_key_create, pthread_getconcurrency **/ #define NANOSLEEP_MAX 100000 //a multiple of 100 (that's the loop step) volatile char blocked; //when unset, signals child that it may exit jmp_buf env; //context storage for sigset and longjmp int pfd[2]; //pipe file descriptors static void handle(int sig); static void block(void); static void* thread(void *fun); #define WRAP_START \ int err = 0; \ if (!setjmp(env)) { \ blocked = 1; \ close(pfd[1]); /*ready*/ #define WRAP_END \ blocked = 0; /*reaching this = failure, see handle() for more info*/ \ } \ return err; static int wrap_pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg); static int wrap_pthread_cancel(pthread_t thread); static int wrap_pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); static int wrap_pthread_setspecific(pthread_key_t key, const void *value); static int wrap_pthread_key_delete(pthread_key_t key); static int wrap_pthread_join(pthread_t thread, void **value_ptr); static int wrap_pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); static int wrap_pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset); static int wrap_pthread_equal(pthread_t t1, pthread_t t2); static int wrap_pthread_setschedprio(pthread_t thread, int prio); static int wrap_pthread_setconcurrency(int new_level); int main() { int8_t x; char *s, c; pid_t pid; pthread_t tid; pthread_key_t tkey; struct timespec ns = {.tv_nsec=0}; unsigned int i, nr_fun, failed; int err, ret[2]={0,0}, stat; const char *function[] = { "pthread_create", "pthread_cancel", "pthread_once", "pthread_setspecific", "pthread_key_delete", "pthread_join", "pthread_atfork", "pthread_sigmask", "pthread_equal", "pthread_setschedprio", "pthread_setconcurrency", "pthread_detach", "pthread_sigmask", "pthread_setspecific", "pthread_key_create", "pthread_rwlock_unlock", "pthread_kill", }; struct { unsigned int kill:1, wait:1; } error, no_error = {.wait=0}; struct sigaction act = {.sa_handler=handle, .sa_flags=SA_NODEFER}; failed = 0; for (i=0; i < (nr_fun=sizeof(function)/sizeof(*function)); ++i) { pipe(pfd); memset(&error, 0, sizeof(error)); if (!(pid = fork())) { close(pfd[0]); blocked = 0; //wrappers set it to 1 after saving env sigaction(SIGTERM, &act, NULL); sigaction(SIGABRT, &act, NULL); pthread_create(&tid, NULL, thread, block); //printf("%i calling.\n", i); //---- switch (i) { case 0: err = wrap_pthread_create(&tid, NULL, thread, NULL); break; case 1: err = wrap_pthread_cancel(tid); break; case 2: err = wrap_pthread_once( (pthread_once_t []){PTHREAD_ONCE_INIT}, block ); break; case 3: if (!pthread_key_create(&tkey, NULL)) { err = wrap_pthread_setspecific(tkey, NULL); pthread_key_delete(tkey); } else err = -3; break; case 4: //key creation(inicialization) done in the wrapper: err = wrap_pthread_key_delete(tkey); break; case 5: err = wrap_pthread_join(tid, NULL); break; case 6: err = wrap_pthread_atfork(NULL, NULL, NULL); break; case 7: err = wrap_pthread_sigmask(SIG_UNBLOCK, NULL, NULL); break; //pthread_equal() returned 1(Operation not permitted) case 8: err = wrap_pthread_equal(tid, tid); break; //pthread_equal() returned 1(Operation not permitted) #ifndef MUSL case 9: err = wrap_pthread_setschedprio( tid, sched_get_priority_min(sched_getscheduler(0)) ); break; #endif case 10: err = wrap_pthread_setconcurrency(pthread_getconcurrency()); break; default: blocked = 0; close(pfd[1]); err = -2; break; } if (setjmp(env)) fprintf(stdout,"BUG: SIGTERM received after function return\n");//---- printf("%d returning.\n", i); //---- return err; } if (!pid) { fprintf(stdout, "BUG: child i=%d escaped!\n", i); exit(0); //exit/contain child }else if (pid == -1) { close(pfd[1]); close(pfd[0]); fprintf(stderr, "A call to fork() nr %d/%d yielded -1 (errno=%s)!\n", i+1, nr_fun, (s = e_name(errno)) ); free(s); failed += 1; }else{ close(pfd[1]); //printf("reading %i.\n", i); //---- read(pfd[0], &c, 1); //wait for the child to become ready close(pfd[0]); //Send SIGABRT to child in delays of microsec: ns.tv_nsec = NANOSLEEP_MAX; while( (ret[0] = kill(pid, SIGABRT)) == 0 && (ret[1] = waitpid(pid, &stat, WNOHANG)) == 0 && (ns.tv_nsec -= 100) ) nanosleep(&ns, NULL); //let child's function out of its loop/blocked state kill(pid, SIGTERM); if (!ns.tv_nsec) { printf("waiting %i.\n", i);//---- waitpid(pid, &stat, 0); } //Process errors: s = e_name(errno); error.kill = (ret[0] != 0); error.wait = (ret[1] != 0 && ret[1] != pid); if (memcmp(&error, &no_error, sizeof(error))) { ++failed; if (error.kill) fprintf(stderr, "A call to kill() returned %d, errno=%s\n", ret[0], s ); if (error.wait) fprintf(stderr, "A call to waitpid() returned %d, errno=%s\n", ret[1], s ); }else if (WIFEXITED(stat)) { if ((x = WEXITSTATUS(stat))) { ++failed; if (x == -2) fprintf(stderr, "%s() or one of its dependencies missing!\n", function[i] ); else if (x == -3) fprintf(stderr, "%s() did not run - its dependency failed\n", function[i] ); else if (x) { free(s); s = e_name(x); fprintf(stderr, "%s() returned %s\n", function[i], s); } } //else printf("%s passed (returned %d)\n", function[i], x); //---- }else{ fprintf(stderr, "%s()'s host process crashed!\n", function[i]); if (WIFSIGNALED(stat)) fprintf(stderr, "\tTerminating signal: %d\n", (int)WTERMSIG(stat) ); } free(s); } } return failed; } /** ** Signal handler. Upon receiving the first SIGTERM it unsets blocked, longjmps ** Otherwise - on another signal or if blocked is unset - it simply returns **/ static void handle(int sig) { if (sig == SIGTERM) { if(blocked) { blocked = 0; longjmp(env, 1); } else {printf("BUG: Misplaced SIGTERM!\n");} //----- } } ///waits for blocked to be unset by a signal[!] via the signal handler, returns static void block(void) { while(blocked) sched_yield(); //can't use pause() - handle() doesn't return on SIGTERM sleep(3);printf("exit block()\n");//--- } /** ** Establishes the function passed to it as a thread cancellation handler and ** calls it. Thus, if the executing thread is canceled, the said function will ** still have to be executed before the thread is terminated. ** \param fun a void* cast of (void (*)()) or NULL (only return) **/ static void* thread(void *fun) { if (fun != NULL) { pthread_cleanup_push(fun, NULL); ((void (*)())fun)(); pthread_cleanup_pop(0); } return NULL; } ///