d498f1c8300de57ab9eefc5caf00629f09e4af0e
[wsti_so.git] / src / process2.c
1 #include <stdio.h>
2 /* exit.. */
3 #include <stdlib.h>
4 /* strsignal... */
5 #include <string.h>
6
7 /* open/read/write/close */
8 #include <fcntl.h>
9
10 /* Signals handling.. */
11 #include <signal.h>
12
13 #include <sys/shm.h>
14
15 /** If buffer is too small to hold entire string, it is incremented by this value */
16 #define BUFFER_STEP 16
17
18 /** Named pipe used to communicate with process1 */
19 char * read_pipe = "/tmp/process1pipe";
20
21 /** Named pipe used to communicate with process3 */
22 char * write_pipe = "/tmp/process2pipe";
23
24 /** Descriptor of input pipe */
25 int read_descriptor;
26
27 /** Descriptor of output pipe */
28 int write_descriptor;
29
30
31 /**
32  * Shared memory variables
33  */
34
35 /**
36  * Memory key for processes. Must be same between all processes to properly
37  * communicate.
38  */
39 key_t shmkey = 18912;
40 /**
41  * Id of the shared memory
42  */
43 int shmid;
44
45 /**
46  * Message shared by processes. Contains array of process IDs
47  */
48 struct message {
49         pid_t pids[3];
50 };
51
52 struct message * processes = NULL;
53
54 /**
55  * Message queue variables
56  */
57 key_t qkey = 12356;
58 int qid;
59
60 struct queue_message {
61         long mtype;
62         int signo[1];
63 };
64
65 void notify_other_processes(int signo) {
66         int i = 0;
67         struct queue_message msg;
68         msg.signo[0] = signo;
69
70         for (; i < 3; i++) {
71                 pid_t pid = processes->pids[i];
72                 // Bleh
73                 if (i != 1 && pid != 0) {
74                         msg.mtype = i+1;
75                         fprintf(stderr, "[%s] Sending message of type (%d) with value %d\n", "process1", msg.mtype, msg.signo[0]);
76                         msgsnd(qid, &msg, sizeof(msg), 0);
77                         fprintf(stderr, "[%s] Sending signal %s (%d) to PID: %d\n", "process2", strsignal(SIGUSR1), SIGUSR1, pid);
78                         kill(pid, SIGUSR1);
79                 }
80         }
81 }
82
83 /**
84  * Handler for signals.
85  */
86 void sig_handler(int signo)
87 {
88         fprintf(stderr, "[%s] Received %s!\n", "process2", strsignal(signo));
89         if (signo == SIGUSR1) {
90                 fprintf(stderr, "[%s] > Notified!\n", "process2");
91                 struct queue_message msg;
92                 /* Check queues from both other processes */
93                 if (msgrcv(qid, &msg, sizeof(int), 2, 0) > 0) {
94                         fprintf(stderr, "[%s] > Notified with value: %s!\n", "process2", strsignal(msg.signo[0]));
95                         raise(msg.signo[0]);
96                 }
97         }
98         else if (signo == SIGTERM) {
99                 fprintf(stderr, "[%s] > Signalling other processes..\n", "process2");
100                 processes->pids[1] = 0;
101                 notify_other_processes(signo);
102
103                 fprintf(stderr, "[%s] > Releasing resources\n", "process2");
104                 close(read_descriptor);
105                 close(write_descriptor);
106                 unlink(write_descriptor);
107                 exit(0);
108         }
109         else if (signo == SIGTSTP) {
110                 fprintf(stderr, "[%s] > Close reading pipe\n", "process2");
111                 close(read_descriptor);
112                 notify_other_processes(signo);
113                 fprintf(stderr, "[%s] > Close writing pipe\n", "process2");
114                 close(write_descriptor);
115                 raise (SIGSTOP);
116         }
117         else if (signo == SIGCONT) {
118                 fprintf(stderr, "[%s] > Signalling other processes..\n", "process2");
119                 notify_other_processes(signo);
120
121                 fprintf(stderr, "[%s] > Opening pipes\n", "process2");
122                 write_descriptor = open(write_pipe, O_WRONLY);
123                 read_descriptor = open(read_pipe, O_RDONLY);
124         }
125 }
126
127 /**
128  * Program grabs data from process1, calculates number of characters in each line
129  * and pass the value to process3.
130  */
131 int main(void) {
132         /**
133          * Buffer used for storing data from input pipe.
134          * Data is stored in chunks of BUFFER_STEP size.
135          * If data during reading is bigger than this value, then number of
136          * characters is saved, and buffer is cleared for reading another chunk.
137          */
138         char buffer[BUFFER_STEP];
139
140         /** Index used when iterating buffer */
141         int i = 0;
142
143         /** Stores number of bytes read from input pipe in current iteration */
144         ssize_t count = 0;
145
146         int number_of_characters = 0;
147
148         fprintf(stderr, "[%s] Init!\n", "process2");
149
150         /**
151          * Register signals handled by process
152          */
153         if (signal(SIGUSR1, sig_handler) == SIG_ERR) {
154                 fprintf(stderr, "can't catch SIGUSR1\n");
155         }
156         if (signal(SIGTERM, sig_handler) == SIG_ERR) {
157                 fprintf(stderr, "can't catch SIGTERM\n");
158         }
159         if (signal(SIGTSTP, sig_handler) == SIG_ERR) {
160                 fprintf(stderr, "can't catch SIGTSTP\n");
161         }
162         if (signal(SIGCONT, sig_handler) == SIG_ERR) {
163                 fprintf(stderr, "can't catch SIGCONT\n");
164         }
165
166         /*
167          * Register memory to share with other processes, and pass current
168          * process id to the array.
169          */
170         shmid = shmget(shmkey, sizeof(struct message), 0666);
171
172         processes = (struct message *)shmat(shmid, NULL, 0);
173         processes->pids[1] = getpid();
174
175         fprintf(stderr, "[%s] Shared pid: %d\n", "process2", getpid());
176
177         /**
178          * Register message queue to communicate with other processes
179          */
180         qid = msgget(qkey, 0666);
181
182         /* Reading from process1 */
183         read_descriptor = open(read_pipe, O_RDONLY);
184
185         /* Writing to process2 */
186         mkfifo(write_pipe, 0666);
187         write_descriptor = open(write_pipe, O_WRONLY);
188
189         while(1) {
190                 /* Read data from input pipe */
191                 count = read(read_descriptor, buffer, BUFFER_STEP);
192
193                 fprintf(stderr, "[%s] Fetched: %d bytes\n", "process2", count);
194
195                 if (count > 0) {
196                         for (i = 0; i < count; i++, number_of_characters++) {
197                                 if (buffer[i] == '\n') {
198                                         fprintf(stderr, "[%s] Calculated: %d characters. Sending...\n", "process2", number_of_characters);
199                                         write(write_descriptor, &number_of_characters, sizeof(number_of_characters));
200                                         write(write_descriptor, '\n', 1);
201                                         number_of_characters = 0;
202                                 }
203                         }
204                 }
205                 else {
206                         break;
207                 }
208         }
209
210         /* Release resources in normal program flow exit. */
211         close(read_descriptor);
212         close(write_descriptor);
213         unlink(write_descriptor);
214
215         return 0;
216 }