File: process_load.c

package info (click to toggle)
contest 0.61-5
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 228 kB
  • ctags: 217
  • sloc: ansic: 2,121; makefile: 98; sh: 3
file content (155 lines) | stat: -rw-r--r-- 3,278 bytes parent folder | download | duplicates (2)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*--------------------------------------------------------------------
  	
  Public domain 2002, Rene Herman.
  
  Background load for the contest benchmark. This load creates a bunch
  of processes shipping a record around a "circular pipe".
  
  Concept from Bob Matthews' process_load as shipped with the irman
  (version 0.5) benchmark.
  
--------------------------------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "sysinfo.h"
#include "trivial.h"
#include "programs.h"
#include "process_load.h"

/* user settable */
#define N 4		   /* number of processes to fork (per CPU) */
#define R (2 * PIPE_BUF)   /* record size: 0 < R <= SSIZE_MAX       */	

extern int opt_pl_nr_procs;

char buf[R];

static int child(int readfd, int writefd)
{
	ssize_t r;

	while ((r = read(readfd, buf, R)) > 0)
		if (write(writefd, buf, r) != r) {
			perror("Write error");
			return EXIT_FAILURE;
		}
	if (r) {
		perror("Read error 1");
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}

static volatile sig_atomic_t term;

static void sigterm(int signum gcc_unused)
{
	term = 1;
}

int do_process_load(void)
{
	int 		 i, n;
	struct sigaction action;
	int		 prevfd[2], currfd[2];
	ssize_t		 r;

	n = N;
	if(!(n=opt_pl_nr_procs)) {
		if(get_cpus(&n)){
			perror("Could not get info on number of processors\n");
			return EXIT_FAILURE;
		}
		n *= N;
	}

	sigemptyset(&action.sa_mask);

	/* children ignore SIGTERM, we handle it globally  */
	action.sa_handler = SIG_IGN;
	action.sa_flags = 0;
	if (sigaction(SIGTERM, &action, NULL) == -1) {
		perror("Could not install signal handler");
		return EXIT_FAILURE;
	}	

	/* create first pipe */
	if (pipe(prevfd) == -1) {
		perror("Could not create pipe");
		return EXIT_FAILURE;
	}

	/* fork n - 1 children for a total of n processes */
	for (i = n - 1; i; i--) {
		if (pipe(currfd) == -1) {
			perror("Could not create pipe");
			return EXIT_FAILURE;
		}	
		switch (fork()) {
		case -1:
			perror("Could not fork");
			return EXIT_FAILURE;
		case 0:
			close(prevfd[1]);
			close(currfd[0]);
			_exit(child(prevfd[0], currfd[1]));
		default:	
			close(prevfd[0]);
			close(currfd[1]);
			prevfd[0] = currfd[0];
		}
	}

	/* establish termination handler */
	action.sa_handler = sigterm;
	action.sa_flags = SA_RESTART;
	if (sigaction(SIGTERM, &action, NULL) == -1) {
		perror("Could not install signal handler");
		return EXIT_FAILURE;
	}	

	/* kick the ball until sigterm */
	while (!term) {
		/* SA_RESTART ensures no EINTR; partial is okay */
		if ((r = write(prevfd[1], buf, R)) == -1) {
			perror("Write error");
			return EXIT_FAILURE;
		}
		if (read(currfd[0], buf, r) == -1) {
			perror("Read error 2");
			return EXIT_FAILURE;
		}
		if(++i==10000){
			report_progress();
			i=0;
		}
	}

	/* close initiates cascade of cleanly exiting children */
	close(prevfd[1]);

	/* if interrupted read(), last child still in write() */
	while ((r = read(currfd[0], buf, R)) > 0);
	if (r) {
		perror("Read error 3");
		return EXIT_FAILURE;
	}

	/* reap 'em and weep */
	while (--n)
		if (wait(NULL) == -1) {
			perror("Could not collect children");
			return EXIT_FAILURE;
		}

	return EXIT_SUCCESS;
}