librnr  1.14.5
RoadNarrows Robotics Common Library 1
example_shm.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RoadNarrows Robotics Common Library 1
4 //
5 // File: example_shm.c
6 //
7 /*! \file
8  *
9  * $LastChangedDate: 2013-02-08 12:20:58 -0700 (Fri, 08 Feb 2013) $
10  * $Rev: 2676 $
11  *
12  * \brief Example of librnr support for shared memory.
13  *
14  * \author Robin Knight (robin.knight@roadnarrows.com)
15  *
16  * \pkgcopyright{2013-2018,RoadNarrows LLC.,http://www.roadnarrows.com}
17  */
18 // Permission is hereby granted, without written agreement and without
19 // license or royalty fees, to use, copy, modify, and distribute this
20 // software and its documentation for any purpose, provided that
21 // (1) The above copyright notice and the following two paragraphs
22 // appear in all copies of the source code and (2) redistributions
23 // including binaries reproduces these notices in the supporting
24 // documentation. Substantial modifications to this software may be
25 // copyrighted by their authors and need not follow the licensing terms
26 // described here, provided that the new terms are clearly indicated in
27 // all files where they apply.
28 //
29 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
30 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
31 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
32 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
33 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
34 // THE POSSIBILITY OF SUCH DAMAGE.
35 //
36 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
37 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
38 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
39 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
40 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
41 //
42 ////////////////////////////////////////////////////////////////////////////////
43 
44 #include <time.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <libgen.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <pthread.h>
51 
52 #include "rnr/rnrconfig.h"
53 #include "rnr/log.h"
54 #include "rnr/opts.h"
55 #include "rnr/shm.h"
56 
57 #include "version.h"
58 
59 //
60 // The command with option and argument values.
61 //
62 static char *Argv0; ///< the command
63 static bool_t OptsNoMutex = false; ///< do [not] disable mutex
64 static bool_t OptsNoColor = false; ///< do [not] disable color esc sequence
65 
66 /*!
67  * \brief Program information.
68  */
70 {
71  .synopsis = "Example of librnr shared memory mutex.",
72 
73  .long_desc =
74  "The %P command forks to separate process, each with two threads that all "
75  "write to stdout. With mutexing enabled, the output should not be "
76  "intereleaved between the processes and threads."
77 };
78 
79 /*!
80  * \brief Command line options information.
81  */
82 static OptsInfo_T OptsInfo[] =
83 {
84  // --no-mutex
85  {
86  .long_opt = "no-mutex",
87  .short_opt = OPTS_NO_SHORT,
88  .has_arg = no_argument,
89  .has_default = true,
90  .opt_addr = &OptsNoMutex,
91  .fn_cvt = OptsCvtArgBool,
92  .fn_fmt = OptsFmtBool,
93  .arg_name = NULL,
94  .opt_desc = "Disable shared memory mutex."
95  },
96 
97  // --no-color
98  {
99  .long_opt = "no-color",
100  .short_opt = OPTS_NO_SHORT,
101  .has_arg = no_argument,
102  .has_default = true,
103  .opt_addr = &OptsNoColor,
104  .fn_cvt = OptsCvtArgBool,
105  .fn_fmt = OptsFmtBool,
106  .arg_name = NULL,
107  .opt_desc = "Disable color coding output."
108  },
109 
110  {NULL, }
111 };
112 
113 /*!
114  * \brief Main initialization.
115  *
116  * \param argc Command-line argument count.
117  * \param argv Command-line argument list.
118  *
119  * \return Returns 1 on success, exits on failure.
120  */
121 static int init(int argc, char *argv[])
122 {
123  // name of this process
124  Argv0 = basename(argv[0]);
125 
126  // parse input options
127  argv = OptsGet(Argv0, &PkgInfo, &PgmInfo, OptsInfo, true, &argc, argv);
128 
129  return 1;
130 }
131 
132 //
133 // State
134 //
135 #define N_PROCS 2 ///< number of processes
136 #define N_THREADS 2 ///< number of threads/process
137 #define WHO_CHILD 0 ///< child process
138 #define WHO_PARENT 1 ///< parent process
139 #define RED_QUEEN 0 ///< red queen identifier
140 #define CHESHIRE_CAT 1 ///< cheshire cat identifier
141 #define WHITE_QUEEN 2 ///< white queen identifier
142 #define MARCH_HARE 3 ///< march hare identifier
143 #define N_AINW_CHARS 4 ///< number of Alice in Wonderland characters
144 #define COLOR_RED_QUEEN LOG_COLOR_PRE LOG_COLOR_LIGHT_RED
145  ///< red queen text color
146 #define COLOR_CHESHIRE_CAT LOG_COLOR_PRE LOG_COLOR_LIGHT_YELLOW
147  ///< cheshire cat text color
148 #define COLOR_WHITE_QUEEN LOG_COLOR_PRE "1;37m"
149  ///< white queen text color
150 #define COLOR_MARCH_HARE LOG_COLOR_PRE LOG_COLOR_LIGHT_BLUE
151  ///< march hare text color
152 #define COLOR_POST LOG_COLOR_POST
153  ///< post color string
154 
155 key_t ShmKey = 0xdead4; ///< share memory key
156 shm_mutex_t ShmMutex; ///< share memory mutex
157 uint_t Seed; ///< random generator seed
158 int Who; ///< who: child or parent process
159 pthread_t Thread[N_THREADS]; ///< thread
160 int ThreadState[N_THREADS]; ///< thread run/die state
161 
162 char *WhoName[N_PROCS] = {" child", "parent"}; ///< process name
163 
164 /*!
165  * \brief Alice in Wonderland character ids.
166  */
168 {
169  {RED_QUEEN, CHESHIRE_CAT}, // child process
170  {WHITE_QUEEN, MARCH_HARE} // parent process
171 };
172 
173 /*!
174  * \brief Alice in Wonderland character names.
175  */
177 {
178  "Red Queen", "Cheshire Cat", // child process
179  "White Queen", "March Hare" // parent process
180 };
181 
182 /*!
183  * \brief Alice in Wonderland character text colors.
184  */
186 {
191 };
192 
193 /*!
194  * \brief Alice in Wonderland character text.
195  */
197 {
198  "Off with their heads, off with their heads!",
199  "Only the insane equate pain with success.",
200  "But I don't forget and I don't forgive.",
201  "Perhaps as this is May I won't be raving mad at least not as March."
202 };
203 
204 /*!
205  * \brief Seed random number generator.
206  */
207 static void randseed()
208 {
209  struct timespec t;
210 
211  clock_gettime(CLOCK_REALTIME, &t);
212  Seed = (uint_t)t.tv_nsec;
213 }
214 
215 /*!
216  * \brief Sleep thread for a random time.
217  *
218  * Actual sleep time will be between [0, max].
219  *
220  * \param max Maximum time to sleep (usec).
221  */
222 static void randusleep(uint_t max)
223 {
224  uint_t n = (uint_t)rand_r(&Seed);
225  float r;
226  uint_t t;
227 
228  r = (float)n / (float)RAND_MAX;
229  t = (uint_t)((float)max * r);
230 
231  usleep(t);
232 }
233 
234 /*!
235  * \brief Lock mutex.
236  */
237 static void lock()
238 {
239  if( !OptsNoMutex )
240  {
241  shm_mutex_lock(&ShmMutex);
242  }
243 }
244 
245 /*!
246  * \brief Unlock mutex.
247  */
248 static void unlock()
249 {
250  if( !OptsNoMutex )
251  {
252  shm_mutex_unlock(&ShmMutex);
253  }
254 }
255 
256 /*!
257  * \brief Thread main.
258  *
259  * \param pArg Pointer to character's id.
260  *
261  * \return Returns NULL.
262  */
263 static void *threadmain(void *pArg)
264 {
265  int me = *(int *)pArg; // character id
266  int n = me - N_THREADS * Who; // thread index
267  char *sColorPre; // precolor string
268  char *sText; // characters text
269  char *sColorPost; // postcolor string
270 
271  LOGDIAG1("%s: %s thread created.", WhoName[Who], AinWCharName[me]);
272 
273  if( OptsNoColor )
274  {
275  sColorPre = "";
276  sText = Say[me];
277  sColorPost = "";
278  }
279  else
280  {
281  sColorPre = Color[me];
282  sText = Say[me];
283  sColorPost = COLOR_POST;
284  }
285 
286  while( ThreadState[n] )
287  {
288  randusleep(100000);
289 
290  lock();
291 
292  //printf("%s%s%s", sColorPre, sText, sColorPost);
293  printf("%s", sColorPre); usleep(10000);
294  printf("%s: ", AinWCharName[me]); usleep(10000);
295  printf("%s", sText); usleep(10000);
296  printf("%s", sColorPost); usleep(10000);
297  printf("\n");
298 
299  unlock();
300  }
301 
302  LOGDIAG1("%s: %s thread killed.", WhoName[Who], AinWCharName[me]);
303 
304  return NULL;
305 }
306 
307 /*!
308  * \brief Create all threads for process.
309  *
310  * \return Ruturns 0 on success, -1 on failure.
311  */
312 static int createThreads()
313 {
314  int i;
315 
316  for(i=0; i<N_THREADS; ++i)
317  {
318  ThreadState[i] = 1;
319 
320  if( pthread_create(&Thread[i], NULL, threadmain, &AinWCharId[Who][i]) != 0 )
321  {
322  LOGSYSERROR("%s: thread %d", WhoName[Who], i);
323  return -1;
324  }
325  }
326 
327  return 0;
328 }
329 
330 /*!
331  * \brief Kill all threads in process.
332  */
333 static void killThreads()
334 {
335  int i;
336 
337  for(i=0; i<N_THREADS; ++i)
338  {
339  ThreadState[i] = 0;
340  pthread_join(Thread[i], NULL);
341  }
342 }
343 
344 /*!
345  * \brief Run example for a process.
346  */
347 static void runExample(int who)
348 {
349  Who = who;
350 
351  randseed();
352  randusleep(1000000);
353 
354  LOGDIAG1("%s: creating shared memory mutex.", WhoName[Who]);
355 
356  if( !OptsNoMutex )
357  {
358  if( shm_mutex_init(ShmKey, &ShmMutex) < 0 )
359  {
360  LOGERROR("%s: failed to create mutex.", WhoName[Who]);
361  }
362  }
363 
364  if( createThreads() < 0 )
365  {
366  return;
367  }
368 
369  switch( Who )
370  {
371  case WHO_CHILD:
372  sleep(3);
373  break;
374  case WHO_PARENT:
375  sleep(4);
376  break;
377  default:
378  break;
379  }
380 
381  killThreads();
382 
383  if( !OptsNoMutex )
384  {
385  shm_mutex_destroy(&ShmMutex);
386  }
387 }
388 
389 /*!
390  * \brief Example main.
391  *
392  * \param argc Command-line argument count.
393  * \param argv Command-line argument list.
394  *
395  * \par Exit Status:
396  * Program exits with 0 success, \h_gt 0 on failure.
397  */
398 int main(int argc, char *argv[])
399 {
400  pid_t pid;
401 
402  if( !init(argc, argv) )
403  {
404  return 2;
405  }
406 
407  switch( (pid = fork()) )
408  {
409  case -1:
410  LOGERROR("Failed to fork child process.");
411  return 8;
412  case 0: // child
414  break;
415  default: // parent
417  break;
418  }
419 
420  return 0;
421 }
static void randseed()
Seed random number generator.
Definition: example_shm.c:207
#define COLOR_POST
post color string
Definition: example_shm.c:152
int OptsCvtArgBool(const char *argv0, const char *sOptName, char *optarg, void *pOptVal)
Convert options boolean argument to bool_t.
Definition: opts.c:1018
#define N_AINW_CHARS
number of Alice in Wonderland characters
Definition: example_shm.c:143
char * Say[4]
Alice in Wonderland character text.
Definition: example_shm.c:196
int AinWCharId[2][2]
Alice in Wonderland character ids.
Definition: example_shm.c:167
int Who
who: child or parent process
Definition: example_shm.c:158
Shared memory interface.
#define WHITE_QUEEN
white queen identifier
Definition: example_shm.c:141
static bool_t OptsNoMutex
do [not] disable mutex
Definition: example_shm.c:63
Standard command-line options options and parsing.
Program Description Strings Info Structure.
Definition: opts.h:226
int shm_mutex_init(key_t key, shm_mutex_t *pshmmutex)
Create and initialize a shared memory mutex.
Definition: shm.c:277
int ThreadState[2]
thread run/die state
Definition: example_shm.c:160
#define NULL
null pointer
Definition: rnrconfig.h:199
char * AinWCharName[4]
Alice in Wonderland character names.
Definition: example_shm.c:176
u32_t uint_t
32-bit unsigned integer
Definition: rnrconfig.h:181
#define LOGDIAG1(fmt,...)
Standard Diagnostic Level 1 logging.
Definition: log.h:407
#define COLOR_RED_QUEEN
red queen text color
Definition: example_shm.c:144
#define LOGSYSERROR(fmt,...)
Standard System Error logging.
Definition: log.h:509
#define CHESHIRE_CAT
cheshire cat identifier
Definition: example_shm.c:140
const char * synopsis
Simple program synopsis string.
Definition: opts.h:240
uint_t Seed
random generator seed
Definition: example_shm.c:157
static char * Argv0
the command
Definition: example_shm.c:62
#define WHO_PARENT
parent process
Definition: example_shm.c:138
#define LOGERROR(fmt,...)
Standard Error logging.
Definition: log.h:488
#define N_PROCS
number of processes
Definition: example_shm.c:135
static void randusleep(uint_t max)
Sleep thread for a random time.
Definition: example_shm.c:222
Shared memory structure type.
Definition: shm.h:39
char * Color[4]
Alice in Wonderland character text colors.
Definition: example_shm.c:185
static const PkgInfo_T PkgInfo
Definition: version.h:45
#define RED_QUEEN
red queen identifier
Definition: example_shm.c:139
key_t ShmKey
share memory key
Definition: example_shm.c:155
#define OPTS_NO_SHORT
no short option equivalent
Definition: opts.h:99
shm_mutex_t ShmMutex
share memory mutex
Definition: example_shm.c:156
#define WHO_CHILD
child process
Definition: example_shm.c:137
char * WhoName[2]
process name
Definition: example_shm.c:162
#define N_THREADS
number of threads/process
Definition: example_shm.c:136
static void * threadmain(void *pArg)
Thread main.
Definition: example_shm.c:263
int bool_t
"boolean" T/F
Definition: rnrconfig.h:187
RoadNarrows Robotics common configuration file.
char ** OptsGet(const char *argv0, const PkgInfo_T *pPkgInfo, OptsPgmInfo_T *pPgmInfo, OptsInfo_T *pOptsInfo, bool_t bHasLogging, int *pargc, char *argv[])
Gets, validates, and sets all command line options.
Definition: opts.c:861
Package version information.
int shm_mutex_lock(shm_mutex_t *pshmmutex)
Lock the mutex.
Definition: shm.c:305
#define COLOR_CHESHIRE_CAT
cheshire cat text color
Definition: example_shm.c:146
int shm_mutex_unlock(shm_mutex_t *pshmmutex)
Unlock a lock the mutex.
Definition: shm.c:396
static void runExample(int who)
Run example for a process.
Definition: example_shm.c:347
static void killThreads()
Kill all threads in process.
Definition: example_shm.c:333
static bool_t OptsNoColor
do [not] disable color esc sequence
Definition: example_shm.c:64
static OptsPgmInfo_T PgmInfo
Program information.
Definition: example_shm.c:69
int shm_mutex_destroy(shm_mutex_t *pshmmutex)
Destroy a shared memory mutex.
Definition: shm.c:300
char * OptsFmtBool(char *buf, size_t buflen, void *pOptVal)
Boolean option value string formatter.
Definition: opts.c:1247
#define COLOR_MARCH_HARE
march hare text color
Definition: example_shm.c:150
#define MARCH_HARE
march hare identifier
Definition: example_shm.c:142
static void unlock()
Unlock mutex.
Definition: example_shm.c:248
#define COLOR_WHITE_QUEEN
white queen text color
Definition: example_shm.c:148
Logger declarations.
static int createThreads()
Create all threads for process.
Definition: example_shm.c:312
const char * long_opt
Long option string name.
Definition: opts.h:137
static OptsInfo_T OptsInfo[]
Command line options information.
Definition: example_shm.c:82
static int init(int argc, char *argv[])
Main initialization.
Definition: example_shm.c:121
pthread_t Thread[2]
thread
Definition: example_shm.c:159
int main(int argc, char *argv[])
Example main.
Definition: example_shm.c:398
Short and Long Options Info.
Definition: opts.h:134
static void lock()
Lock mutex.
Definition: example_shm.c:237