Browse Source

libposix: deep refactor; add sys/posixly command

With these changes, libposix (and newlib) can run MirBSD Korn Shell.
master
Giacomo Tesio 5 years ago
parent
commit
001069aa7b
  1. 2
      cfg/mksh/profile
  2. 5
      qa/check
  3. 10
      qa/kern/awake.c
  4. 2
      qa/lib/c/qlockt2.c
  5. 4
      qa/lib/c/rlockt1.c
  6. 2
      qa/lib/c/rlockt2.c
  7. 2
      qa/lib/c/rsleept2.c
  8. 2
      qa/lib/c/wlockt2.c
  9. 7
      qa/lib/newlib/001-hello.c
  10. 27
      qa/lib/newlib/002-atexit.c
  11. 44
      qa/lib/newlib/041-env.c
  12. 32
      qa/lib/newlib/041-env.runner
  13. 71
      qa/lib/newlib/050-setsid.c
  14. 2
      qa/lib/newlib/050-setsid.runner
  15. 48
      qa/lib/newlib/120-fcntl.c
  16. 82
      qa/lib/newlib/121-fcntl.c
  17. 7
      qa/lib/newlib/200-signals.c
  18. 7
      qa/lib/newlib/201-signals.c
  19. 6
      qa/lib/newlib/202-signals.c
  20. 8
      qa/lib/newlib/203-signals.c
  21. 6
      qa/lib/newlib/204-signals.c
  22. 51
      qa/lib/newlib/206-signals.c
  23. 74
      qa/lib/newlib/207-sigsuspend.c
  24. 69
      qa/lib/newlib/208-sigpending.c
  25. 54
      qa/lib/newlib/209-sigwaitinfo.c
  26. 58
      qa/lib/newlib/210-sigtimedwait.c
  27. 61
      qa/lib/newlib/211-sigtimedwait.c
  28. 54
      qa/lib/newlib/212-sigwait.c
  29. 88
      qa/lib/newlib/213-sigqueue.c
  30. 132
      qa/lib/newlib/214-sigsetjmp.c
  31. 38
      qa/lib/newlib/215-sigprocmask.c
  32. 36
      qa/lib/newlib/build.json
  33. 20
      qa/lib/newlib/libposix_customization.c
  34. 20
      qa/lib/newlib/libposix_sigchld.c
  35. 271
      sys/include/posix.h
  36. 6
      sys/src/cmd/sys/build.json
  37. 4
      sys/src/lib/libs.json
  38. 22
      sys/src/lib/posix/build.json
  39. 96
      sys/src/lib/posix/environment.c
  40. 35
      sys/src/lib/posix/errors.c
  41. 159
      sys/src/lib/posix/fcntl.c
  42. 71
      sys/src/lib/posix/files.c
  43. 217
      sys/src/lib/posix/ids.c
  44. 84
      sys/src/lib/posix/initlib.c
  45. 86
      sys/src/lib/posix/internal.h
  46. 50
      sys/src/lib/posix/kill.c
  47. 9
      sys/src/lib/posix/others.c
  48. 1941
      sys/src/lib/posix/posixly.c
  49. 124
      sys/src/lib/posix/processes.c
  50. 223
      sys/src/lib/posix/sigchlds.c
  51. 558
      sys/src/lib/posix/signals.c
  52. 49
      sys/src/lib/posix/sigqueue.c
  53. 292
      sys/src/lib/posix/sigsets.c
  54. 46
      sys/src/lib/posix/sigsuspend.c
  55. 62
      sys/src/lib/posix/termios.c
  56. 7
      sys/src/lib/posix/timers.c

2
cfg/mksh/profile

@ -0,0 +1,2 @@
export PWD=`cat /dev/wdir`
export HOSTNAME=$SYSNAME

5
qa/check

@ -2,6 +2,11 @@
rfork
if( ! test -d /dev/posix ){
sys/posixly -d /tmp/qa-posixly.log -p $PID &
# sys/ctrace -o /tmp/posixly.trace $APID &
}
dir=$1
if(~ $dir '') dir=/qa

10
qa/kern/awake.c

@ -74,7 +74,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000);
if(verbose)
fprint(2, "rendezvous interrupted, returned %#p, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || elapsed < 900 || elapsed > 1300){
if(!awakened(wkup) || elapsed < 900 || elapsed > 1800){
print("FAIL: rendezvous\n");
exits("FAIL");
}
@ -105,7 +105,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000);
if(verbose)
print("semacquire(&sem, 1): returned %lld, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1300){
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1800){
print("FAIL: semacquire\n");
exits("FAIL");
}
@ -113,8 +113,8 @@ main(void)
/* verify that tsemacquire are NOT interrupted */
fprint(2, "verify that tsemacquire are NOT interrupted\n", elapsed);
wkup = awake(700);
start = nsec();
wkup = awake(500);
res = tsemacquire(&sem, 1500);
elapsed = (nsec() - start) / (1000 * 1000);
if(verbose)
@ -137,7 +137,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000);
if(verbose)
fprint(2, "read(fds[0], buf, 1) returned %lld, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1300){
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1800){
print("FAIL: read\n");
exits("FAIL");
}
@ -155,7 +155,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000);
if(verbose)
fprint(2, "writeTillBlock(fds[0]) returned %lld, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || res >= 256 || elapsed < 900 || elapsed > 1300){
if(!awakened(wkup) || res >= 256 || elapsed < 900 || elapsed > 1800){
print("FAIL: write\n");
exits("FAIL");
}

2
qa/lib/c/qlockt2.c

@ -208,7 +208,7 @@ main(int argc, char* argv[])
}
average = average / NPROC / (1000 * 1000);
if(average < 300) /* we asked for 1ms... we are dumb, after all */
if(average < 1000) /* we asked for 1ms... we are dumb, after all */
{
print("PASS\n");
exits("PASS");

4
qa/lib/c/rlockt1.c

@ -112,7 +112,7 @@ waiter(int index)
if(verbose)
print("reader %d: got the rlock in %lld ms\n", getpid(), (end - start) / (1000*1000));
runlock(&afterAWhile);
if((end - start) / (1000*1000) > 1500)
if((end - start) / (1000*1000) > 2000)
postnote(PNGROUP, getpid(), smprint("fail: reader %d got the rlock after %lld ms", getpid(), (end - start) / (1000*1000)));
} else {
if(verbose)
@ -127,7 +127,7 @@ waiter(int index)
rwakeup(&rCompleted);
qunlock(&rl);
return (end - start) / (1000*1000) < 1300 ? nil : "FAIL";
return (end - start) / (1000*1000) < 2000 ? nil : "FAIL";
}
void

2
qa/lib/c/rlockt2.c

@ -214,7 +214,7 @@ main(int argc, char* argv[])
}
average = average / NPROC / (1000 * 1000);
if(average < 300) /* we asked for 1ms... we are dumb, after all */
if(average < 800) /* we asked for 1ms... we are dumb, after all */
{
print("PASS\n");
exits("PASS");

2
qa/lib/c/rsleept2.c

@ -215,7 +215,7 @@ main(int argc, char* argv[])
}
average = average / NPROC / (1000 * 1000);
if(average < 500) /* we asked for 1ms... we are dumb, after all */
if(average < 1000) /* we asked for 1ms... we are dumb, after all */
{
print("PASS\n");
exits("PASS");

2
qa/lib/c/wlockt2.c

@ -210,7 +210,7 @@ main(int argc, char* argv[])
}
average = average / NPROC / (1000 * 1000);
if(average < 300) /* we asked for 1ms... we are dumb, after all */
if(average < 1000) /* we asked for 1ms... we are dumb, after all */
{
print("PASS\n");
exits("PASS");

7
qa/lib/newlib/001-hello.c

@ -0,0 +1,7 @@
#include <stdio.h>
int main()
{
fprintf(stdout, "hello, stdout\n");
fprintf(stderr, "hello, stderr\n");
return 0;
}

27
qa/lib/newlib/002-atexit.c

@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void
bye(void)
{
printf("That was all, folks\n");
exit(0);
}
int
main(void)
{
// long a;
int i;
// a = sysconf(_SC_ATEXIT_MAX);
// printf("ATEXIT_MAX = %ld\n", a);
i = atexit(bye);
if (i != 0) {
fprintf(stderr, "cannot set exit function\n");
return 1;
}
return 2;
}

44
qa/lib/newlib/041-env.c

@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main ()
{
int child, status;
printf("Parent $PATH = %s\n", getenv("PATH"));
printf("Parent $HOME = %s\n", getenv("HOME"));
printf("Parent $USER = %s\n", getenv("USER"));
printf("Parent $IFS = %s\n", getenv("IFS"));
printf("Parent $ROOT = %s\n", getenv("ROOT"));
printf("Parent $TEST = %s\n", getenv("TEST"));
putenv("TEST=value");
printf("Parent putenv(TEST=value); now $TEST = %s\n", getenv("TEST"));
fflush(stdout);
switch(child = fork()){
case 0:
printf("Child $PATH = %s\n", getenv("PATH"));
printf("Child $HOME = %s\n", getenv("HOME"));
printf("Child $USER = %s\n", getenv("USER"));
printf("Child $IFS = %s\n", getenv("IFS"));
printf("Child $ROOT = %s\n", getenv("ROOT"));
printf("Child $TEST = %s\n", getenv("TEST"));
exit(0);
case -1:
printf("FAIL: fork\n");
return 1;
default:
wait(&status);
break;
}
unsetenv("TEST");
printf("Parent unsetenv(TEST); now $TEST = %s\n", getenv("TEST"));
if(status)
printf("FAIL: child returned %d\n", status);
exit(status);
}

32
qa/lib/newlib/041-env.runner

@ -0,0 +1,32 @@
#!/cmd/rc
runner=$0
test = `{echo $runner|sed 's/.runner//'}
test_output = /tmp/output-`{basename $test}
if ( test -e $test_output) rm $test_output
$test > $test_output
expected_lines = ('Parent \$PATH = /cmd:.' \
'Parent \$HOME = '^$HOME \
'Parent \$USER = '^$USER \
'Parent \$ROOT = \(null\)' \
'Parent \$TEST = \(null\)' \
'Parent putenv\(TEST=value\); now \$TEST = value' \
'Child \$PATH = /cmd:.' \
'Child \$HOME = '^$HOME \
'Child \$USER = '^$USER \
'Child \$ROOT = \(null\)' \
'Child \$TEST = value' \
'Parent unsetenv\(TEST\); now \$TEST = \(null\)' \
PASS )
for (line in $expected_lines) {
if ( ! cat $test_output | grep $"line > /dev/null ) {
cat $test_output
echo FAIL: can not find line: $line
exit FAIL
}
}
echo PASS
exit PASS

71
qa/lib/newlib/050-setsid.c

@ -11,43 +11,46 @@ main(int argc, char **argv)
int p[2], ppgrp, opgrp, npgrp;
char c = '?';
if (pipe(p) != 0)
if (pipe(p) != 0){
perror("pipe() error");
else {
ppgrp = getpgrp();
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
if ((pid = fork()) == 0) {
opgrp = getpgrp();
printf("child's pid %d; process group id %d\n", getpid(), opgrp);
write(p[1], &c, 1);
setsid();
npgrp = getpgrp();
if(opgrp == npgrp){
printf("FAIL: setsid did not changed child's process group id\n");
exit(EXIT_FAILURE);
}
printf("child's process group id is now %d\n", npgrp);
sleep(5);
exit(EXIT_SUCCESS);
} else {
read(p[0], &c, 1);
sleep(3);
if(ppgrp != getpgrp()){
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp());
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
ppgrp = getpgrp();
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
if ((pid = fork()) == 0) {
opgrp = getpgrp();
printf("child's pid %d; process group id %d\n", getpid(), opgrp);
if(setsid() == -1){
write(p[1], "e", 1);
perror("FAIL: setsid");
exit(EXIT_FAILURE);
}
write(p[1], &c, 1);
npgrp = getpgrp();
if(opgrp == npgrp){
printf("FAIL: setsid did not changed child's process group id\n");
exit(EXIT_FAILURE);
}
printf("child's process group id is now %d\n", npgrp);
sleep(5);
exit(EXIT_SUCCESS);
} else {
read(p[0], &c, 1);
sleep(3);
if(c == 'e')
exit(EXIT_FAILURE);
if(ppgrp != getpgrp()){
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp());
exit(EXIT_FAILURE);
}
#ifndef WITH_SIGCHLD
npgrp = getsid(pid);
if(npgrp < 0){
printf("FAIL: parent's getsid(%d) failed with errno %d\n", pid, errno);
exit(EXIT_FAILURE);
}
if(npgrp == ppgrp){
printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
exit(EXIT_FAILURE);
}
#endif
npgrp = getsid(pid);
if(npgrp == ppgrp){
printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
exit(EXIT_FAILURE);
}
#endif
exit(EXIT_SUCCESS);
}
}

2
qa/lib/newlib/050-setsid.runner

@ -5,7 +5,7 @@ test_output = /tmp/output-`{basename $test}
if ( test -e $test_output) rm $test_output
$test $test_output > /dev/null
$test > $test_output
if ( cat $test_output | grep 'FAIL' > /dev/null ) {
cat $test_output
echo FAIL

48
qa/lib/newlib/120-fcntl.c

@ -0,0 +1,48 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
// see http://www.informit.com/articles/article.aspx?p=99706&seqNum=13
int
main(int argc, char *argv[])
{
int fd, accmode, val;
if (argc != 2)
fd = 0;
else
fd = atoi(argv[1]);
if ( (val = fcntl(fd, F_GETFL, 0)) < 0){
perror("fcntl error for fd");
exit(1);
}
printf("fcntl(%d) returns %d\n", fd, val);
accmode = val & O_ACCMODE;
if (accmode == O_RDONLY)
printf("read only");
else if (accmode == O_WRONLY)
printf("write only");
else if (accmode == O_RDWR)
printf("read write");
else {
perror("unknown access mode");
exit(1);
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
#if !defined(_POSIX_SOURCE) && defined(O_SYNC)
if (val & O_SYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}

82
qa/lib/newlib/121-fcntl.c

@ -0,0 +1,82 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
void
fail_if_still_open(int fd)
{
if(fd == 0){
printf("atoi failed\n");
exit(2);
}
if(fcntl(fd, F_GETFD) != -1){
printf("fd %d is still open\n", fd);
exit(3);
}
}
int
main(int argc, char *argv[])
{
int sync[2];
int outfd;
int nullfd;
int tmp;
char *eargv[7], *p;
char buf[128];
if(argc == 1){
printf("cat /proc/%d/fd\n", getpid());
pipe(sync);
outfd = dup(1);
nullfd = open("/dev/null", O_WRONLY);
tmp = fcntl(sync[0], F_DUPFD_CLOEXEC, 1);
close(sync[0]);
sync[0] = tmp;
tmp = fcntl(sync[1], F_DUPFD_CLOEXEC, 1);
close(sync[1]);
sync[1] = tmp;
tmp = fcntl(outfd, F_DUPFD_CLOEXEC, 1);
close(outfd);
outfd = tmp;
tmp = fcntl(nullfd, F_DUPFD_CLOEXEC, 1);
close(nullfd);
nullfd = tmp;
eargv[0] = argv[0];
p = buf;
eargv[1] = p;
p += 1+sprintf(p, "%d", sync[0]);
eargv[2] = p;
p += 1+sprintf(p, "%d", sync[1]);
eargv[3] = p;
p += 1+sprintf(p, "%d", outfd);
eargv[4] = p;
p += 1+sprintf(p, "%d", nullfd);
eargv[5] = NULL;
execvp(argv[0], eargv);
printf("execvp returned\n");
exit(100);
} else if(argc != 5){
printf("argc = %d (should be 5)\n", argc);
exit(1);
}
printf("argc = %d; fds: %s %s %s %s\n", argc, argv[1], argv[2], argv[3], argv[4] );
sync[0] = atoi(argv[1]);
sync[1] = atoi(argv[2]);
outfd = atoi(argv[3]);
nullfd = atoi(argv[4]);
fail_if_still_open(sync[0]);
fail_if_still_open(sync[1]);
fail_if_still_open(outfd);
fail_if_still_open(nullfd);
exit(0);
}

7
qa/lib/newlib/200-signals.c

@ -58,6 +58,7 @@ main() {
signal(SIGQUIT, sigquit);
printf("\nChild going to loop...\n\n");
write(p[1], "", 1);
close(p[1]);
close(p[0]);
for(;;); /* loop for ever */
@ -65,11 +66,11 @@ main() {
else /* parent */
{
signal(SIGCHLD,sigchld);
close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
if(read(p[0], &dummy, 1) != 1){
printf("sync read");
exit(EXIT_FAILURE);
}
close(p[1]);
close(p[0]);
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid,SIGHUP);

7
qa/lib/newlib/201-signals.c

@ -26,6 +26,7 @@ main() {
if (pid == 0) {
printf("\nI am the new child!\n\n");
write(p[1], "", 1);
close(p[1]);
close(p[0]);
for(;;){
@ -36,11 +37,11 @@ main() {
}
else /* parent */
{
close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
if(read(p[0], &dummy, 1) != 1){
printf("sync read");
exit(EXIT_FAILURE);
}
close(p[1]);
close(p[0]);
printf("\nPARENT: sending SIGINT\n\n");
kill(pid,SIGINT);

6
qa/lib/newlib/202-signals.c

@ -28,6 +28,7 @@ main() {
if (pid == 0) {
signal(SIGCONT,sigcont); /* set function calls */
printf("Child going to loop...\n");
write(p[1], "", 1);
close(p[1]);
close(p[0]);
for(;;){
@ -38,11 +39,8 @@ main() {
}
else /* parent */
{
read(p[0], &dummy, 1);
close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
exit(EXIT_FAILURE);
}
close(p[0]);
printf("PARENT: sending SIGCONT\n\n");
kill(pid,SIGCONT);

8
qa/lib/newlib/203-signals.c

@ -22,7 +22,8 @@ void childloop(void)
{
signal(SIGCONT,sigcont); /* set function calls */
signal(SIGSTOP,sigstop); /* set function calls */
printf("Child going to loop...\n");
printf("Child %d going to loop...\n", getpid());
write(p[1], "", 1);
close(p[1]);
close(p[0]);
for(;;){
@ -54,11 +55,8 @@ main() {
}
else /* parent */
{
read(p[0], &dummy, 1);
close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
exit(EXIT_FAILURE);
}
close(p[0]);
sleep(2);
printf("PARENT: sending SIGSTOP\n");

6
qa/lib/newlib/204-signals.c

@ -47,6 +47,7 @@ main() {
signal(SIGQUIT, sigquit);
printf("Child going to loop...\n");
write(p[1], "", 1);
close(p[1]);
close(p[0]);
for(;;); /* loop for ever */
@ -54,11 +55,8 @@ main() {
else /* parent */
{
signal(SIGCHLD,sigchld);
read(p[0], &dummy, 1);
close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
exit(EXIT_FAILURE);
}
close(p[0]);
printf("PARENT: sending SIGHUP\n");
kill(pid,SIGHUP);

51
qa/lib/newlib/206-signals.c

@ -0,0 +1,51 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void sigusr1() {
printf("Got SIGUSR1\n");
exit(0);
}
int
main()
{
sigset_t old_set, new_set;
sigemptyset(&old_set);
sigemptyset(&new_set);
signal(SIGUSR1, sigusr1);
if(sigaddset(&new_set, SIGSEGV) == 0)
{
printf("sigaddset successfully added for SIGSEGV\n");
}
sigprocmask(SIG_BLOCK, &new_set, &old_set);
printf("raise(SIGSEGV)\n");
raise(SIGSEGV);
if(sigaddset(&new_set, SIGUSR1) == 0)
{
printf("sigaddset successfully added for SIGUSR1\n");
}
if(sigprocmask(SIG_BLOCK, &new_set, &old_set) == -1)
{
perror("sigprocmask");
}
printf("raise(SIGUSR1)\n");
raise(SIGUSR1);
sigemptyset(&new_set);
sigaddset(&new_set, SIGUSR1);
printf("unblock SIGUSR1 via sigprocmask\n");
if(sigprocmask(SIG_UNBLOCK, &new_set, &old_set) == -1)
{
perror("sigprocmask");
}
return 1;
}

74
qa/lib/newlib/207-sigsuspend.c

@ -0,0 +1,74 @@
#define _POSIX_SOURCE
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
int SIGUSR1_caught;
int SIGUSR2_caught;
void catcher(int signum) {
switch (signum) {
case SIGUSR1:
++SIGUSR1_caught;
puts("catcher caught SIGUSR1");
if(SIGUSR2_caught){
puts("FAIL: SIGUSR2 already caught");
exit(1);
}
break;
case SIGUSR2:
++SIGUSR2_caught;
puts("catcher caught SIGUSR2");
break;
default:
printf("catcher caught unexpected signal %d\n", signum);
}
}
int
main()
{
sigset_t sigset;
struct sigaction sact;
time_t t;
if (fork() == 0) {
printf("child is %d\n", getpid());
sleep(10);
puts("child is sending SIGUSR2 signal - which should be blocked");
kill(getppid(), SIGUSR2);
sleep(5);
puts("child is sending SIGUSR1 signal - which should be caught");
kill(getppid(), SIGUSR1);
exit(0);
}
sigemptyset(&sact.sa_mask);
sact.sa_flags = 0;
sact.sa_handler = catcher;
if (sigaction(SIGUSR1, &sact, NULL) != 0)
perror("1st sigaction() error");
else if (sigaction(SIGUSR2, &sact, NULL) != 0)
perror("2nd sigaction() error");
else {
sigfillset(&sigset);
sigdelset(&sigset, SIGUSR1);
time(&t);
printf("parent is waiting for child to send SIGUSR1 at %s",
ctime(&t));
if (sigsuspend(&sigset) == -1)
perror("sigsuspend() returned -1 as expected");
time(&t);
printf("sigsuspend is over at %s", ctime(&t));
}
if(SIGUSR1_caught != 1)
printf("SIGUSR1_caught is %d\n", SIGUSR1_caught);
if(SIGUSR2_caught != 1)
printf("SIGUSR2_caught is %d\n", SIGUSR2_caught);
if(SIGUSR1_caught != 1 || SIGUSR2_caught != 1)
exit(2);
exit(0);
}

69
qa/lib/newlib/208-sigpending.c

@ -0,0 +1,69 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void catcher(int sig) {
puts("Got SIGUSR1");
}
int check_pending(int sig, char *signame) {
sigset_t sigset;
if(sigpending(&sigset) != 0){
perror("sigpending() error\n");
exit(1);
}
if(sigismember(&sigset, sig)){
printf("a %s (%d) signal is pending\n", signame, sig);
return 1;
} else {
printf("no %s (%d) signals are pending\n", signame, sig);
return 0;
}
}
int main(int argc, char *argv[]) {
struct sigaction sigact;
sigset_t sigset;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
if(sigaction(SIGUSR1, &sigact, NULL) != 0){
perror("sigaction() error\n");
return 2;
}
printf("Calling sigprocmask to block SIGUSR1...\n");
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
if (sigprocmask(SIG_SETMASK, &sigset, NULL) != 0){
perror("sigprocmask() error\n");
return 3;
}
printf("SIGUSR1 signals are now blocked\n");
kill(getpid(), SIGUSR1);
printf("kill(getpid(), SIGUSR1) DONE\n");
if(!check_pending(SIGUSR1, "SIGUSR1")){
printf("FAIL: SIGUSR1 is not pending despite the mask\n");
return 4;
}
printf("Calling sigprocmask to unblock SIGUSR1...\n");
sigemptyset(&sigset);
sigprocmask(SIG_SETMASK, &sigset, NULL);
printf("SIGUSR1 signals are no longer blocked\n");
if(check_pending(SIGUSR1, "SIGUSR1")){
printf("FAIL: SIGUSR1 is still pending despite the mask\n");
return 4;
}
return 0;
}

54
qa/lib/newlib/209-sigwaitinfo.c

@ -0,0 +1,54 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
alarm(3);
timestamp("before sigwaitinfo()");
result = sigwaitinfo(&waitset, &info);
err = errno;
timestamp("after sigwaitinfo()");
if(result > 0){
printf("sigwaitinfo() returned for signal %d\n", info.si_signo);
return 0;
}
printf("sigwaitinfo() returned %d; errno = %d\n", result, err);
perror("sigwaitinfo() function failed");
return 1;
}

58
qa/lib/newlib/210-sigtimedwait.c

@ -0,0 +1,58 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s\n", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
struct timespec timeout;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
timeout.tv_sec = 4; /* Number of seconds to wait */
timeout.tv_nsec = 1000; /* Number of nanoseconds to wait */
alarm(2);
timestamp("before sigtimedwait()");
result = sigtimedwait(&waitset, &info, &timeout);
err = errno;
timestamp("after sigtimedwait()");
if(result > 0){
printf("sigtimedwait() returned for signal %d\n", info.si_signo);
return 0;
}
printf("sigtimedwait() returned %d; errno = %d\n", result, err);
perror("sigtimedwait() function failed");
return 1;
}

61
qa/lib/newlib/211-sigtimedwait.c

@ -0,0 +1,61 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s\n", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
struct timespec timeout;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
timeout.tv_sec = 1; /* Number of seconds to wait */
timeout.tv_nsec = 1000; /* Number of nanoseconds to wait */
alarm(4);
timestamp("before sigtimedwait()");
result = sigtimedwait(&waitset, &info, &timeout);
err = errno;
timestamp("after sigtimedwait()");
if(result > 0){
printf("sigtimedwait() returned for signal %d\n", info.si_signo);
return 1;
}
printf("sigtimedwait() returned %d; errno = %d\n", result, err);
if(err != EAGAIN){
perror("errno is not EAGAIN");
return 2;
}
return 0;
}

54
qa/lib/newlib/212-sigwait.c

@ -0,0 +1,54 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
int sig;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
alarm(3);
timestamp("before sigwait()");
result = sigwait(&waitset, &sig);
err = errno;
timestamp("after sigwait()");
if(result == 0){
printf("sigwait() returned for signal %d\n", sig);
return 0;
}
printf("sigwait() returned %d; errno = %d\n", result, err);
perror("sigwait() function failed");
return 1;
}

88
qa/lib/newlib/213-sigqueue.c

@ -0,0 +1,88 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
void catcher(int sig, siginfo_t *info, void *p) {
printf("Signal catcher called for signal %d from %d\n", sig, info->si_pid);
exit(1);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s", str, ctime(&t));
}
void echoSIGUSR1(void){
int result;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
union sigval v;
printf("CHILD pid %d\n", getpid());
v.sival_int = 0;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = catcher;
sigaction(SIGUSR1, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGUSR1);
sigprocmask(SIG_BLOCK, &waitset, NULL);
while(v.sival_int < 5){
result = sigwaitinfo(&waitset, &info);
v.sival_int = 1 + info.si_value.sival_int;
printf("CHILD sigqueue %d to %d\n", v.sival_int, info.si_pid);
sigqueue(info.si_pid, result, v);
}
}
int main(int argc, char *argv[]) {
int result;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
union sigval v;
pid_t child;
switch(child = fork()){
case 0:
echoSIGUSR1();
exit(0);
break;
case -1:
exit(1);
break;
default:
break;
}
printf("PARENT pid %d sleep(3)\n", getpid());
sleep(3);
v.sival_int = 0;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = catcher;
sigaction(SIGUSR1, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGUSR1);
sigprocmask(SIG_BLOCK, &waitset, NULL);
result = SIGUSR1;
do{
printf("PARENT sigqueue %d\n", v.sival_int);
sigqueue(child, result, v);
result = sigwaitinfo(&waitset, &info);
v.sival_int = 1 + info.si_value.sival_int;
} while(v.sival_int < 5);
exit(0);
}

132
qa/lib/newlib/214-sigsetjmp.c

@ -0,0 +1,132 @@
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
sigset_t sigset;
sigjmp_buf mark;
int catcherWasCalled;
void catcher(int);
void p(void);
int main(int argc, char *argv[]) {
int result = 0;
int returnCode = 0;
/*
* Block the SIGUSR2 signal. This signal set will be
* saved as part of the environment by the sigsetjmp()
* function and subsequently restored by the siglongjmp()
* function.
*/
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR2);
sigprocmask(SIG_SETMASK, &sigset, NULL);
/* Save the stack environment and the current signal mask */
returnCode = sigsetjmp(mark, 1);
/* Handle the sigsetjmp return code */
switch(returnCode) {
case 0:
printf("sigsetjmp() has been called\n");
/*
* Call function p() which will call the siglongjmp()
* function
*/
p();
printf("control returning here is an error\n");
result=-1;
break;
case -1:
printf("siglongjmp() function was called\n");
/* Retrieve the current signal mask */
sigprocmask(SIG_SETMASK, NULL, &sigset);
/* Verify SIGUSR2 is in sigset */
if(sigismember(&sigset, SIGUSR2)) {
printf("signal mask was restored after siglongjmp()\n");
result=0;
} else {
printf("signal mask was not restored after siglongjmp()\n");
result=-1;
}
break;
default:
printf("this unexpected return code is an error\n");
result=-1;
break;
}
printf("return from main with result %d\n", result);
return result;
}
void p(void) {
struct sigaction sigact;
int error=0;
printf("performing function p()\n");
/* Setup signal handler in case error condition is detected */
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGUSR2, &sigact, NULL);
/*
* Delete SIGUSR2 from the signal set that was initialized
* by the main() function. This allows us to demonstrate
* that the original signal set saved by the sigsetjmp() function
* is restored by the siglongjmp() function.
*/
sigdelset(&sigset, SIGUSR2);
sigprocmask(SIG_SETMASK, &sigset, NULL);
/* After some processing an error condition is detected */
error=-1;
/* Call catcher() function if error is detected */
if(error != 0) {
catcherWasCalled = 0;
/* Send SIGUSR2 to handle the error condition */
printf("error condition detected, send SIGUSR2 signal\n");
kill(getpid(), SIGUSR2);
if(catcherWasCalled == 1) {
printf("catcher() function handled the error condition\n");
/*
* Perform a nonlocal "goto" and specify -1 for the
* return value
*/
siglongjmp(mark, -1);
printf("control getting here is an error\n");
exit(3);
}
}
}
void catcher(int signo) {
/*
* Indicate the catcher() function is handling the
* SIGUSR2 signal.
*/
catcherWasCalled = 1;
}

38
qa/lib/newlib/215-sigprocmask.c

@ -0,0 +1,38 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
sigset_t parent_mask;
int
main()
{
int status;
sigset_t mask;
sigprocmask(SIG_BLOCK, NULL, &parent_mask);
sigaddset(&parent_mask, SIGSEGV);
sigprocmask(SIG_BLOCK, &parent_mask, NULL);
printf("SIGSEGV blocked in parent. Forking...\n");
switch(fork()){
case -1:
exit(1);
case 0:
sigprocmask(SIG_BLOCK, NULL, &mask);
printf("Is SIGSEGV (%llx) a member of %llx?\n", 1ULL<<(SIGSEGV-1), (long long unsigned int)mask);
if(sigismember(&mask, SIGSEGV) != 1){
printf("FAIL: SIGSEGV is not present in child's mask after fork\n");
exit(2);
}
printf("PASS\n");
exit(0);
default:
wait(&status);
status = WEXITSTATUS(status);
exit(status);
}
}

36
qa/lib/newlib/build.json

@ -32,22 +32,37 @@
],
"SourceFilesCmd": [
"000-hello.c",
"001-hello.c",
"002-atexit.c",
"010-fork.c",
"020-waitpid.c",
"030-pause.c",
"031-setjmp.c",
"040-gettimeofday.c",
"041-env.c",
"050-setsid.c",
"100-files.c",
"101-files.c",
"102-files.c",
"103-files.c",
"120-fcntl.c",
"121-fcntl.c",
"200-signals.c",
"201-signals.c",
"202-signals.c",
"203-signals.c",
"204-signals.c",
"205-signals.c"
"205-signals.c",
"206-signals.c",
"207-sigsuspend.c",
"208-sigpending.c",
"209-sigwaitinfo.c",
"210-sigtimedwait.c",
"211-sigtimedwait.c",
"212-sigwait.c",
"213-sigqueue.c",
"214-sigsetjmp.c",
"215-sigprocmask.c"
]
},
"SIGCHLDTests": {
@ -84,20 +99,37 @@
],
"SourceFilesCmd": [
"000-hello.c",
"001-hello.c",
"002-atexit.c",
"010-fork.c",
"020-waitpid.c",
"030-pause.c",
"031-setjmp.c",
"040-gettimeofday.c",
"041-env.c",
"050-setsid.c",
"100-files.c",
"101-files.c",
"102-files.c",
"103-files.c",
"120-fcntl.c",
"121-fcntl.c",
"200-signals.c",
"201-signals.c",
"202-signals.c",
"203-signals.c",
"204-signals.c",
"205-signals.c"
"205-signals.c",
"206-signals.c",
"207-sigsuspend.c",
"208-sigpending.c",
"209-sigwaitinfo.c",
"210-sigtimedwait.c",
"211-sigtimedwait.c",
"212-sigwait.c",
"213-sigqueue.c",
"214-sigsetjmp.c",
"215-sigprocmask.c"
]
},
"NewlibTestsuite": {

20
qa/lib/newlib/libposix_customization.c

@ -27,18 +27,34 @@ qa_exit_translator(int status)
* should return PASS/FAIL
*/
if(status == 0){
jehanne_print("PASS\n");
return "PASS";
} else {
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
return "FAIL";
}
}
return nil;
}
void
qa_exit_printer(int status, void *_)
{
extern int printf(const char *format, ...);
if(jehanne_getpid() == jehanne_getmainpid()){
/* the QA test may fork, but only the main process
* should return PASS/FAIL
*/
if(status == 0){
printf("PASS\n");
} else {
printf("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
}
}
}
void
__application_newlib_init(void)
{
extern int on_exit(void (*func)(int, void*), void* arg);
on_exit(qa_exit_printer, nil);
libposix_translate_exit_status(qa_exit_translator);
}

20
qa/lib/newlib/libposix_sigchld.c

@ -27,19 +27,35 @@ qa_exit_translator(int status)
* should return PASS/FAIL
*/
if(status == 0){
jehanne_print("PASS\n");
return "PASS";
} else {
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
return "FAIL";
}
}
return nil;
}
void
qa_exit_printer(int status, void *_)
{
extern int printf(const char *format, ...);
if(jehanne_getpid() == jehanne_getmainpid()){
/* the QA test may fork, but only the main process
* should return PASS/FAIL
*/
if(status == 0){
printf("PASS\n");
} else {
printf("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
}
}
}
void
__application_newlib_init(void)
{
extern int on_exit(void (*func)(int, void*), void* arg);
on_exit(qa_exit_printer, nil);
libposix_translate_exit_status(qa_exit_translator);
libposix_emulate_SIGCHLD();
}

271
sys/include/posix.h

@ -30,12 +30,18 @@
* #include <u.h>
* #include <posix.h>
*
* Defining _LIBPOSIX_H before the include allow you to just get dirent
* definition.
* Defining _LIBPOSIX_H before the include allow you to just get
* data structure definition.
*/
#ifndef _LIBPOSIX_DIRENT
#define _LIBPOSIX_DIRENT
#ifndef _LIBPOSIX_DEF
#define _LIBPOSIX_DEF
struct timespec
{
long tv_sec;
long tv_nsec;
};
/* dirent alias of stat(5) message.
* We (ab)use the fact that both 9P and Jehanne are little endian.
@ -75,13 +81,7 @@ struct __attribute__((__packed__)) dirent
#define DT_SOCK 12
#define DT_WHT 14
#endif /* _LIBPOSIX_DIRENT */
#ifndef _LIBPOSIX_H
#define _LIBPOSIX_H