summaryrefslogtreecommitdiff
path: root/user/progR.c
blob: 1d47f6bef274159b21ce76ea13117fa11a293416 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <common.h>

/**
** User function R:   exit, sleep, write, fork, getpid, getppid,
**
** Reports itself and its sequence number, along with its PID and
** its parent's PID. It then delays, forks, delays, reports again,
** and exits.
**
** Invoked as:  userR  x  n  [ s ]
**	 where x is the ID character
**		   n is the sequence number of the initial incarnation
**		   s is the initial delay time (defaults to 10)
*/

USERMAIN( main ) {
	char ch = 'r';	// default character to print
	int delay = 10;	// initial delay count
	int seq = 99;	// my sequence number
	char buf[128];

	// process the command-line arguments
	switch( argc ) {
	case 4:	delay = str2int( argv[3], 10 );
			// FALL THROUGH
	case 3:	seq = str2int( argv[2], 10 );
			// FALL THROUGH
	case 2:	ch = argv[1][0];
			break;
	default:
			sprint( buf, "userR: argc %d, args: ", argc );
			cwrites( buf );
			for( int i = 0; i <= argc; ++i ) {
				sprint( buf, " %s", argv[argc] ? argv[argc] : "(null)" );
				cwrites( buf );
			}
			cwrites( "\n" );
	}

	/*
	** C oddity: a label cannot immediately precede a declaration.
	**
	** Declarations are not considered "statements" in C. Prior to
	** C99, all declarations had to precede any statements inside a
	** block. Labels can only appear before statements.  C99 allowed
	** the mixing of declarations and statements, but did not relax
	** the requirement that labels precede only statements.
	**
	** That's why the declarations of these variables occur before the
	** label, but their initializations occur after the label.
	**
	** As the PSA says on TV, "The more you know..." :-)
	*/

	int32_t pid;
	int32_t ppid;

 restart:

	// announce our presence
	pid = getpid();
	ppid = getppid();

	sprint( buf, " %c[%d,%d,%d]", ch, seq, pid, ppid );
	swrites( buf );

	sleep( SEC_TO_MS(delay) );

	// create the next child in sequence
	if( seq < 5 ) {
		++seq;
		int32_t n = fork();
		switch( n ) {
		case -1:
			// failure?
			sprint( buf, "** R[%d] fork code %d\n", pid, n );
			cwrites( buf );
			break;
		case 0:
			// child
			goto restart;
		default:
			// parent
			--seq;
			sleep( SEC_TO_MS(delay) );
		}
	}

	// final report - PPID may change, but PID and seq shouldn't
	pid = getpid();
	ppid = getppid();
	sprint( buf, " %c[%d,%d,%d]", ch, seq, pid, ppid );
	swrites( buf );

	exit( 0 );

	return( 42 );  // shut the compiler up!

}