automotive-dlt
dlt-test-multi-process.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
27 /*******************************************************************************
28 ** **
29 ** SRC-MODULE: dlt-test-multi-process.c **
30 ** **
31 ** TARGET : linux **
32 ** **
33 ** PROJECT : DLT **
34 ** **
35 ** AUTHOR : Lassi Marttala Lassi.LM.Marttala@partner.bmw.de **
36 ** **
37 ** PURPOSE : Stress test timing using multiple processes **
38 ** **
39 ** REMARKS : Requires POSIX fork() **
40 ** **
41 ** PLATFORM DEPENDANT [yes/no]: yes **
42 ** **
43 ** TO BE CHANGED BY USER [yes/no]: no **
44 ** **
45 *******************************************************************************/
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <unistd.h>
50 #include <limits.h>
51 #include <signal.h>
52 #include <errno.h>
53 #include <pthread.h>
54 #include <sys/wait.h>
55 #include <syslog.h>
56 
57 #include "dlt.h"
58 #include "dlt_common.h"
59 #include "dlt-test-multi-process.h"
60 
61 // Constants
62 #define MAX_PROCS 100
63 #define MAX_THREADS 100
64 
65 // Structs
66 typedef struct {
67  int nmsgs; // Number of messages to send
68  int nprocs; // Number of processes to start
69  int nthreads; // Number of threads to start
70  int delay; // Delay between logs messages for each process
71  int delay_fudge; // Fudge the delay by 0-n to cause desynchronization
72 } s_parameters;
73 
74 typedef struct {
78 
79 // Forward declarations
80 void init_params(s_parameters * params);
81 void quit_handler(int signum);
82 void cleanup();
83 void do_forks(s_parameters params);
84 void run_threads(s_parameters params);
86 int wait_for_death();
87 
88 // State information
89 volatile sig_atomic_t in_handler = 0;
90 
91 // Globals for cleanup from main and signal handler
92 pid_t pids[MAX_PROCS];
93 unsigned int pidcount = 0;
94 
98 void usage(char *prog_name)
99 {
100  char version[255];
101  dlt_get_version(version,255);
102  s_parameters defaults;
103  init_params(&defaults);
104 
105  printf("Usage: %s [options]\n", prog_name);
106  printf("Test application for stress testing the daemon with multiple processes and threads.\n");
107  printf("%s\n", version);
108  printf("Options (Default):\n");
109  printf(" -m number Number of messages per thread to send. (%d)\n", defaults.nmsgs);
110  printf(" -p number Number of processes to start. (%d), Max %d.\n", defaults.nprocs, MAX_PROCS);
111  printf(" -t number Number of threads per process. (%d), Max %d.\n", defaults.nthreads, MAX_THREADS);
112  printf(" -d delay Delay in milliseconds to wait between log messages. (%d)\n", defaults.delay);
113  printf(" -f delay Random fudge in milliseconds to add to delay. (%d)\n", defaults.delay_fudge);
114 }
115 
119 void init_params(s_parameters * params) {
120  params->nmsgs = 100;
121  params->nprocs = 10;
122  params->nthreads = 2;
123  params->delay = 1000;
124  params->delay_fudge = 100;
125 }
126 
130 int read_cli(s_parameters *params, int argc, char **argv)
131 {
132  int c;
133  opterr = 0;
134  while ((c = getopt (argc, argv, "m:p:t:d:f:")) != -1)
135  {
136  switch(c)
137  {
138  case 'm':
139  params->nmsgs = atoi(optarg);
140  break;
141  case 'p':
142  params->nprocs = atoi(optarg);
143  if(params->nprocs > MAX_PROCS)
144  {
145  fprintf(stderr, "Too many processes selected.\n");
146  return -1;
147  }
148  break;
149  case 't':
150  params->nthreads = atoi(optarg);
151  if(params->nprocs > MAX_PROCS)
152  {
153  fprintf(stderr, "Too many threads selected.\n");
154  return -1;
155  }
156  break;
157  case 'd':
158  params->delay = atoi(optarg);
159  break;
160  case 'f':
161  params->delay_fudge = atoi(optarg);
162  break;
163  case '?':
164  if(optopt == 'n' || optopt == 'd' || optopt == 'f')
165  {
166  fprintf(stderr, "Option -%c requires an argument.\n", optopt);
167  }
168  else if(isprint(optopt))
169  {
170  fprintf(stderr, "Unknown option '-%c'.\n", optopt);
171  }
172  else
173  {
174  fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
175  }
176  return -1;
177  break;
178  default:
179  abort();
180  return -1;//for parasoft
181  }
182  }
183  return 0;
184 }
185 
189 int main(int argc, char **argv)
190 {
191  // Prepare parameters
192  s_parameters params;
193  init_params(&params);
194  if(read_cli(&params, argc, argv) != 0) {
195  usage(argv[0]);
196  exit(-1);
197  }
198 
199  // Launch the child processes
200  do_forks(params);
201 
202  // Register signal handlers
203  if(signal(SIGINT, quit_handler) == SIG_IGN)
204  signal(SIGINT, SIG_IGN); // C-c
205  if(signal(SIGHUP, quit_handler) == SIG_IGN)
206  signal(SIGHUP, SIG_IGN); // Terminal closed
207  if(signal(SIGTERM, quit_handler) == SIG_IGN)
208  signal(SIGTERM, SIG_IGN); // kill (nice)
209 
210  printf("Setup done. Listening. My pid: %d\n", getpid());
211  fflush(stdout);
212 
213  int err = wait_for_death();
214  cleanup();
215  return err;
216 }
217 
222 void do_forks(s_parameters params)
223 {
224  int i;
225 
226  // Launch child processes
227  for(i=0;i<params.nprocs;i++)
228  {
229  pid_t pid = fork();
230  switch(pid)
231  {
232  case -1: // An error occured
233  if(errno == EAGAIN)
234  {
235  fprintf(stderr, "Could not allocate resources for child process.\n");
236  cleanup();
237  abort();
238  }
239  if(errno == ENOMEM)
240  {
241  fprintf(stderr, "Could not allocate memory for child process' kernel structure.\n");
242  cleanup();
243  abort();
244  }
245  break;
246  case 0: // Child process, start threads
247  run_threads(params);
248  break;
249  default: // Parent process, store the childs pid
250  pids[pidcount++] = pid;
251  break;
252  }
253  }
254 }
255 
260 void quit_handler(int signum)
261 {
262  if(in_handler)
263  raise(signum);
264  in_handler = 1;
265 
266  cleanup();
267 
268  signal(signum, SIG_DFL);
269  raise(signum);
270 }
271 
275 void cleanup()
276 {
277  unsigned int i;
278  for(i=0;i<pidcount;i++)
279  {
280  kill(pids[i], SIGINT);
281  }
282 }
283 
287 time_t mksleep_time(int delay, int fudge)
288 {
289  if (!fudge)
290  return delay*1000;
291  else
292  return (delay+rand()%fudge)*1000;
293 }
294 
299 {
301  char ctid[5];
302  char ctid_name[256];
303 
304 
305  snprintf(ctid,5,"%.2x", rand() & 0x0000ffff);
306  snprintf(ctid_name,256, "Child %s in dlt-test-multi-process", ctid);
307  DLT_REGISTER_CONTEXT(mycontext, ctid, ctid_name);
308 
309  int msgs_left = data->params.nmsgs;
310  while(msgs_left-- > 0)
311  {
313  usleep(mksleep_time(data->params.delay, data->params.delay_fudge));
314  }
315  DLT_UNREGISTER_CONTEXT(mycontext);
316 }
317 
322 {
323  pthread_t thread[params.nthreads];
324  s_thread_data thread_data;
325  char apid[5];
326  char apid_name[256];
327  int i;
328 
329  srand(getpid());
330 
331  snprintf(apid,5,"MT%02u", pidcount);
332  snprintf(apid_name,256, "Apps %s.", apid);
333 
334  DLT_REGISTER_APP(apid, apid_name);
335 
336  thread_data.params = params;
337 
338  for(i=0;i<params.nthreads;i++)
339  {
340  if(pthread_create(&(thread[i]), NULL, (void *) &do_logging, &thread_data) != 0)
341  {
342  printf("Error creating thread.\n");
343  abort();
344  }
345  }
346 
347  for(i=0;i<params.nthreads;i++)
348  {
349  pthread_join(thread[i], NULL);
350  }
351 
352 
354  // We can exit now
355  exit(0);
356 }
357 
362 {
363  int pids_left = pidcount;
364  while(pids_left > 0)
365  {
366  int status;
367  pid_t w = waitpid(WAIT_ANY, &status, 0);
368  if(status < 0)
369  {
370  return -1;
371  }
372  else
373  {
374  unsigned int i;
375  for(i=0;i<pidcount;i++)
376  {
377  if(pids[i] == w)
378  {
379  pids_left--;
380  break;
381  }
382  }
383  }
384  }
385  return 0;
386 }
#define DLT_UNREGISTER_APP()
void do_forks(s_parameters params)
void do_logging(s_thread_data *data)
#define MAX_THREADS
time_t mksleep_time(int delay, int fudge)
static char data[kDataSize]
Definition: city-test.cc:40
#define DLT_REGISTER_APP(APPID, DESCRIPTION)
unsigned int pidcount
#define DLT_STRING(TEXT)
int main(int argc, char **argv)
#define DLT_REGISTER_CONTEXT(CONTEXT, CONTEXTID, DESCRIPTION)
pid_t pids[MAX_PROCS]
#define MAX_PROCS
#define DLT_UNREGISTER_CONTEXT(CONTEXT)
volatile sig_atomic_t in_handler
#define DLT_LOG(CONTEXT, LOGLEVEL, ARGS...)
void cleanup()
int read_cli(s_parameters *params, int argc, char **argv)
void run_threads(s_parameters params)
void dlt_get_version(char *buf, size_t size)
Definition: dlt_common.c:3239
void init_params(s_parameters *params)
DltContext mycontext
void quit_handler(int signum)
#define PAYLOAD_DATA
int wait_for_death()
void usage(char *prog_name)
#define NULL
Definition: dlt_common.h:232