Signals, Pulses, and Messages in C

Sorry. Signals don’t rate capslock, tbh. But I shall attempt to teach you about them.

The usual includes. msg.h is my teachers’ concoction, and may be found here.

1

2

3

4

5

6

7

8

#include &lt;stdio.h&gt;

#include &lt;sys/neutrino.h&gt;

#include "msg.h"

#include &lt;stdlib.h&gt;

#include &lt;string.h&gt;

#include &lt;sys/netmgr.h&gt;

#include &lt;process.h&gt;

#include &lt;time.h&gt;

Gonna need some globals – the main and a couple of helpter functions both need to access the logfile, the channel id, and the timestruct.

1

2

3

//globals

FILE *logfile;

intchid;

1

2

//for timestamps

time_t timestruct;

Begin!

1

intmain(intargc,char*argv[]){

1

printf("Logger has started.\n");

Initialize the timestruct, cos it is no longer 1970 and I am not Dennis Ritchie.

1

timestruct=time(NULL);

The void pointer – a promise of a method, soon to be revealed.

1

2

3

4

5

//declare functions

intsetupPulseAndTimer();

intsetupSignalAndTimer();

inthandleMessage(intheader,MESSAGE theMessage,intrcvid);

voidhandleSignal(intsignalNum);

That logfile declaration from above? Time to use it! This is nothing more than a textfile where your program is going to write some stuff down.

1

2

//open the log file for writing

logfile=fopen(argv[1],"w");

A couple more variables; theMessage is a handle for data that is received from the client. rcvid will be used to tell the client which of it’s many messages you are currently replying to.

1

2

intrcvid;

MESSAGE theMessage;

Upon startup, this message logger will report its process id, channel id, and node descriptor, and log that info in a pidfile. As I write this I can’t help noticing that chid isn’t initialized yet. I really hope I figure out an explanation for that later.

1

//handle pidfile

1

2

//declare the file

FILE *pidfile;

1

2

//get it's location from the command line

char*pidFileName=malloc(strlen(argv[0])+5);

1

2

3

4

5

//tack .pid on the end just in case, you should probably

//wrap that in an "if not .pid, add .pid" for robustness,

//but I'm living dangerously.

strcpy(pidFileName,argv[0]);

strcat(pidFileName,".pid");

1

2

//open that sucker up

pidfile=fopen(pidFileName,"w");

1

2

3

//write stuff down and hope you don't

//get a null pointer exception from that chid

fprintf(pidfile,"%d %d %d \n",ND_LOCAL_NODE,getpid(),chid);

1

2

3

//close up and let it go.

fclose(pidfile);

free(pidFileName);

This bit is kinda weird. These two functions are both at the bottom of this program, so you’re sending pulses and signals to yourself. Why do that? Narcissism? Shpakism? Just do it.

This is also weird. You’re bascially announcing, “Hey, a signal might show up, and if it does, here’s what you do.” And that instruction is standing orders for the rest of the program, or til you change it.

1

signal(SIGUSR2,&amp;handleSignal);

K, with all that established, begin a for loop that will run until further notice, taking messages and reporting them in the logfile.

1

2

for(;;){

rcvid=MsgReceive(chid,&amp;theMessage,sizeof(theMessage),NULL);

Now, this part confuses me. Cause I thought that a pulse was just a message, with a rcvid of zero. But the teacher has us, apparently, handling two cases that both match the definition of “pulse” in my mind.

So, the first “if” handles rcvid == 0.

1

2

3

4

5

6

if(rcvid==0){

//When pulse arrives log it along with the code that was received.

fprintf(logfile,"%s Pulse received - CODE %d \n",

ctime(&amp;timestruct),theMessage.pulse.code);

printf("%s: Pulse received and logged.\n",ctime(&amp;timestruct));

}

The second “if” redirects to a helper method that has the same big switch statement from my previous post. It also handles a “pulse”, and like I said, I’m confused. However, I swear to god this code runs and drive as written.

Take note of the timeToQuit int there. It takes the return value of the handleMessage function – if the message was a … sigh … pulse, I guess … it returns something other than zero, which terminates the loop, and the program.

1

2

3

4

5

6

7

8

9

10

else{

inttimeToQuit=handleMessage(theMessage.client.m_hdr,

theMessage,rcvid);

printf("%s: Message received and logged. \n",ctime(&amp;timestruct));

if(timeToQuit!=0){

fclose(logfile);

exit(EXIT_SUCCESS);

}

}

}//end for loop

1

2

return0;

}//end main

So where are these pulses and signals coming from? Upsettingly, they are coming from within this very program.

Here’s the setup for a pulse. It is straight out of Getting Started With QNX Neutrino, which can be found here, page 152. RTFM fools.

1

intsetupPulseAndTimer(){

1

2

//Create a timer that sends a pulse and code MSG_PULSE_ALIVE

//3 sec after startup and every 5 sec thereafter

1

2

3

4

timer_t timerid;

structsigevent event;

structitimerspec timer;

intcoid;

1

coid=ConnectAttach(0,0,chid,0,0);

1

2

3

4

5

if(coid==-1){

fprintf(stderr,"Logger: couldn’t ConnectAttach to self!\n");

perror(NULL);

exit(EXIT_FAILURE);

}

1

2

SIGEV_PULSE_INIT(&amp;event,coid,SIGEV_PULSE_PRIO_INHERIT,

MSG_PULSE_ALIVE,0);

1

2

3

4

5

6

if(timer_create(CLOCK_REALTIME,&amp;event,&amp;timerid)==-1){

fprintf(stderr,"Logger: couldn’t create a timer, errno %d\n",

errno);

perror(NULL);

exit(EXIT_FAILURE);

}

1

2

3

4

timer.it_value.tv_sec=3;//three seconds after startup...

timer.it_value.tv_nsec=0;

timer.it_interval.tv_sec=5;//and every five thereafter.

timer.it_interval.tv_nsec=0;

1

timer_settime(timerid,0,&amp;timer,NULL);

1

2

3

return0;//return zero so my error checking printf above works.

}

The signal setup works almost exactly the same, there’s like one line that’s different.

1

2

3

4

5

6

7

8

intsetupSignalAndTimer(){

//Create a timer that sends a signal SIGUSR2 2 seconds after

//startup and every 7 seconds thereafter.

timer_t timerid;

structsigevent event;

structitimerspec timer;

intcoid;

1

2

3

4

5

6

7

coid=ConnectAttach(0,0,chid,0,0);

if(coid==-1){

fprintf(stderr,"Logger: couldn’t ConnectAttach to self!\n");

perror(NULL);

exit(EXIT_FAILURE);

}

1

2

3

//this is the line that's different.

SIGEV_SIGNAL_INIT(&amp;event,SIGUSR2);timer_create

(CLOCK_REALTIME,&amp;event,&amp;timerid);

1

2

3

4

5

6

if(timer_create(CLOCK_REALTIME,&amp;event,&amp;timerid)==-1){

fprintf(stderr,"Logger: couldn’t create a timer, errno %d\n",

errno);

perror(NULL);

exit(EXIT_FAILURE);

}

1

2

3

4

timer.it_value.tv_sec=2;

timer.it_value.tv_nsec=0;

timer.it_interval.tv_sec=7;

timer.it_interval.tv_nsec=0;

1

timer_settime(timerid,0,&amp;timer,NULL);

1

2

return0;

}

My message handler. It logs a message if a message turns up, and shuts the whole show down if a confusingly explained pulse shows up.

1

inthandleMessage(intheader,MESSAGE theMessage,intrcvid){

1

charreply[512];

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

switch(header){

//if message type is MSG_DATA, log message and replay MSG_OK

case(MSG_DATA):

fprintf(logfile,"%s %s \n",ctime(&amp;timestruct),

theMessage.client.m_data);

printf("Message logged. \n");

strcpy(reply,"Message logged. \n");

intrepBytes=sizeof(reply);

MsgReply(rcvid,MSG_OK,reply,repBytes);

fflush(logfile);

break;

//if message type is MSG_END, reply MSG_END then exit

case(MSG_END):

fprintf(logfile,"%s Pulse recieved - server exiting.\n",

ctime(&amp;timestruct));

MsgReply(rcvid,MSG_END,NULL,NULL);

fflush(logfile);

return1;

//break;

//if it is neither of these, reply MSG_INVALID and log incident.

default:

fprintf(logfile,"Warning: invalid message format received.\n");

MsgReply(rcvid,MSG_INVALID,NULL,NULL);

break;

}

return0;

}

And finally, the signal handler. It’s pretty easy.

1

2

3

voidhandleSignal(intsignalNum){

fflush(logfile);

}

And that’s the whole mess. It runs on my machine; I take no responsibility if it causes your computer to have a stroke instead. Here’s the finished code.