3 * Copyright (C) 2012 BMW AG
5 * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
7 * Contributions are licensed to the GENIVI Alliance under one or more
8 * Contribution License Agreements.
11 * This Source Code Form is subject to the terms of the
12 * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with
13 * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
16 * \author Lassi Marttala <Lassi.LM.Marttala@partner.bmw.de> BMW 2011-2012
18 * \file dlt-test-multi-process.c
19 * For further information see http://www.genivi.org/.
23 /*******************************************************************************
25 ** SRC-MODULE: dlt-test-multi-process.c **
31 ** AUTHOR : Lassi Marttala Lassi.LM.Marttala@partner.bmw.de **
33 ** PURPOSE : Stress test timing using multiple processes **
35 ** REMARKS : Requires POSIX fork() **
37 ** PLATFORM DEPENDANT [yes/no]: yes **
39 ** TO BE CHANGED BY USER [yes/no]: no **
41 *******************************************************************************/
54 #include "dlt_common.h"
55 #include "dlt-test-multi-process.h"
59 #define MAX_THREADS 100
63 int nmsgs; // Number of messages to send
64 int nprocs; // Number of processes to start
65 int nthreads; // Number of threads to start
66 int delay; // Delay between logs messages for each process
67 int delay_fudge; // Fudge the delay by 0-n to cause desynchronization
75 // Forward declarations
76 void init_params(s_parameters * params);
77 void quit_handler(int signum);
79 void do_forks(s_parameters params);
80 void run_threads(s_parameters params);
81 void do_logging(s_thread_data *data);
85 volatile sig_atomic_t in_handler = 0;
87 // Globals for cleanup from main and signal handler
88 pid_t pids[MAX_PROCS];
89 unsigned int pidcount = 0;
94 void usage(char *prog_name)
97 dlt_get_version(version,255);
98 s_parameters defaults;
99 init_params(&defaults);
101 printf("Usage: %s [options]\n", prog_name);
102 printf("Test application for stress testing the daemon with multiple processes and threads.\n");
103 printf("%s\n", version);
104 printf("Options (Default):\n");
105 printf(" -m number Number of messages per thread to send. (%d)\n", defaults.nmsgs);
106 printf(" -p number Number of processes to start. (%d), Max %d.\n", defaults.nprocs, MAX_PROCS);
107 printf(" -t number Number of threads per process. (%d), Max %d.\n", defaults.nthreads, MAX_THREADS);
108 printf(" -d delay Delay in milliseconds to wait between log messages. (%d)\n", defaults.delay);
109 printf(" -f delay Random fudge in milliseconds to add to delay. (%d)\n", defaults.delay_fudge);
113 * Set nice default values for parameters
115 void init_params(s_parameters * params) {
118 params->nthreads = 2;
119 params->delay = 1000;
120 params->delay_fudge = 100;
124 * Read the command line and modify parameters
126 int read_cli(s_parameters *params, int argc, char **argv)
130 while ((c = getopt (argc, argv, "m:p:t:d:f:")) != -1)
135 params->nmsgs = atoi(optarg);
138 params->nprocs = atoi(optarg);
139 if(params->nprocs > MAX_PROCS)
141 fprintf(stderr, "Too many processes selected.\n");
146 params->nthreads = atoi(optarg);
147 if(params->nprocs > MAX_PROCS)
149 fprintf(stderr, "Too many threads selected.\n");
154 params->delay = atoi(optarg);
157 params->delay_fudge = atoi(optarg);
160 if(optopt == 'n' || optopt == 'd' || optopt == 'f')
162 fprintf(stderr, "Option -%c requires an argument.\n", optopt);
164 else if(isprint(optopt))
166 fprintf(stderr, "Unknown option '-%c'.\n", optopt);
170 fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
176 return -1;//for parasoft
185 int main(int argc, char **argv)
187 // Prepare parameters
189 init_params(¶ms);
190 if(read_cli(¶ms, argc, argv) != 0) {
195 // Launch the child processes
198 // Register signal handlers
199 if(signal(SIGINT, quit_handler) == SIG_IGN)
200 signal(SIGINT, SIG_IGN); // C-c
201 if(signal(SIGHUP, quit_handler) == SIG_IGN)
202 signal(SIGHUP, SIG_IGN); // Terminal closed
203 if(signal(SIGTERM, quit_handler) == SIG_IGN)
204 signal(SIGTERM, SIG_IGN); // kill (nice)
206 printf("Setup done. Listening. My pid: %d\n", getpid());
209 int err = wait_for_death();
215 * Start the child processes
218 void do_forks(s_parameters params)
222 // Launch child processes
223 for(i=0;i<params.nprocs;i++)
228 case -1: // An error occured
231 fprintf(stderr, "Could not allocate resources for child process.\n");
237 fprintf(stderr, "Could not allocate memory for child process' kernel structure.\n");
242 case 0: // Child process, start threads
245 default: // Parent process, store the childs pid
246 pids[pidcount++] = pid;
253 * Clean up the child processes.
254 * Reraise signal to default handler.
256 void quit_handler(int signum)
264 signal(signum, SIG_DFL);
269 * Ask the child processes to die
274 for(i=0;i<pidcount;i++)
276 kill(pids[i], SIGINT);
281 * Generate the next sleep time
283 time_t mksleep_time(int delay, int fudge)
288 return (delay+rand()%fudge)*1000;
292 * Open logging channel and proceed to spam messages
294 void do_logging(s_thread_data *data)
296 DltContext mycontext;
301 snprintf(ctid,5,"%.2x", rand() & 0x0000ffff);
302 snprintf(ctid_name,256, "Child %s in dlt-test-multi-process", ctid);
303 DLT_REGISTER_CONTEXT(mycontext, ctid, ctid_name);
305 int msgs_left = data->params.nmsgs;
306 while(msgs_left-- > 0)
308 DLT_LOG(mycontext, DLT_LOG_INFO, DLT_STRING(PAYLOAD_DATA));
309 usleep(mksleep_time(data->params.delay, data->params.delay_fudge));
311 DLT_UNREGISTER_CONTEXT(mycontext);
315 * Start the threads and wait for them to return.
317 void run_threads(s_parameters params)
319 pthread_t thread[params.nthreads];
320 s_thread_data thread_data;
327 snprintf(apid,5,"MT%02u", pidcount);
328 snprintf(apid_name,256, "Apps %s.", apid);
330 DLT_REGISTER_APP(apid, apid_name);
332 thread_data.params = params;
334 for(i=0;i<params.nthreads;i++)
336 if(pthread_create(&(thread[i]), NULL, (void *) &do_logging, &thread_data) != 0)
338 printf("Error creating thread.\n");
343 for(i=0;i<params.nthreads;i++)
345 pthread_join(thread[i], NULL);
349 DLT_UNREGISTER_APP();
355 * Wait for child processes to complete their work.
359 int pids_left = pidcount;
363 pid_t w = waitpid(WAIT_ANY, &status, 0);
371 for(i=0;i<pidcount;i++)