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;
}
|