[FIX] missing prototypes: add missing "void"
[platform/core/system/swap-manager.git] / daemon / threads.c
1 /*
2  *  DA manager
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Jaewon Lim <jaewon81.lim@samsung.com>
9  * Woojin Jung <woojin2.jung@samsung.com>
10  * Juyoung Kim <j0.kim@samsung.com>
11  * Cherepanov Vitaliy <v.cherepanov@samsung.com>
12  * Nikita Kalyazin    <n.kalyazin@samsung.com>
13  *
14  * Licensed under the Apache License, Version 2.0 (the "License");
15  * you may not use this file except in compliance with the License.
16  * You may obtain a copy of the License at
17  *
18  * http://www.apache.org/licenses/LICENSE-2.0
19  *
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the License is distributed on an "AS IS" BASIS,
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23  * See the License for the specific language governing permissions and
24  * limitations under the License.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  * - Samsung RnD Institute Russia
29  *
30  */
31
32
33 #include <stdio.h>
34 #include <stdlib.h>                     // for atoi, atol
35 #include <string.h>                     // for strchr
36 #include <stdint.h>                     // for uint64_t
37 #include <sys/types.h>          // for recv
38 #include <sys/socket.h>         // for recv
39 #include <sys/time.h>           // for setitimer
40 #include <signal.h>                     // for sigemptyset, sigset_t, sigaddset, ...
41 #include <unistd.h>                     // for write
42
43 #include "daemon.h"
44 #include "utils.h"
45 #include "sys_stat.h"
46
47 #include "da_protocol.h"
48 #include "da_data.h"
49 #include "debug.h"
50 #include "buffer.h"
51 #include "input_events.h"
52
53 static void* recvThread(void* data)
54 {
55         __da_target_info *target = data;
56         int pass = 0;
57         uint64_t event;
58         ssize_t recvLen;
59         msg_target_t log;
60
61         // initialize target variable
62         target->pid = -1;
63         target->allocmem = 0;
64
65         while(1)
66         {
67                 // read from target process
68                 recvLen = recv(target->socket, &log,
69                                 sizeof(log.type) + sizeof(log.length),
70                                MSG_WAITALL);
71
72                 if(unlikely(recvLen < sizeof(log.type) + sizeof(log.length)))
73                 {       // disconnect
74                         event = EVENT_STOP;
75                         write(target->event_fd, &event, sizeof(uint64_t));
76                         break;
77                 }
78                 if (IS_PROBE_MSG(log.type)) {
79                         struct msg_data_t tmp_msg;
80                         int offs = sizeof(log.type) + sizeof(log.length);
81
82                         recvLen = recv(target->socket,
83                                        (char *)&log + offs,
84                                        MSG_DATA_HDR_LEN - offs,
85                                        MSG_WAITALL);
86                         memcpy(&tmp_msg, &log, MSG_DATA_HDR_LEN);
87                         struct msg_data_t *msg = malloc(MSG_DATA_HDR_LEN +
88                                                         tmp_msg.len);
89                         memcpy(msg, &tmp_msg, MSG_DATA_HDR_LEN);
90                         recvLen = recv(target->socket,
91                                        (char *)msg + MSG_DATA_HDR_LEN,
92                                        msg->len, MSG_WAITALL);
93                         write_to_buf(msg);
94                         free(msg);
95                         continue;
96                 }
97
98                 // send to host
99                 if (likely(log.length > 0))
100                 {
101                         recvLen = recv(target->socket, log.data, log.length,
102                                        MSG_WAITALL);
103                         if(unlikely((recvLen == -1) || (recvLen != log.length)))        // consume as disconnect
104                         {
105                                 event = EVENT_STOP;
106                                 write(target->event_fd, &event, sizeof(uint64_t));
107                                 break;
108                         }
109                 }
110
111                 log.data[log.length] = '\0';
112                 if(log.type == MSG_ALLOC)
113                 {
114                         target->allocmem = str_to_int64(log.data);
115                         continue;               // don't send to host
116                 }
117                 else if(log.type == MSG_PID)
118                 {
119                         LOGI("MSG_PID arrived : %s\n", log.data);
120
121                         // only when first MSG_PID is arrived
122                         if(target->pid == -1)
123                         {
124                                 char* barloc;
125                                 barloc = strchr(log.data, '|');
126                                 if(barloc == NULL)
127                                 {
128                                         /**
129                                          * TODO: complain to host about wrong
130                                          * pid message send stop message to
131                                          * main thread
132                                          */
133                                         event = EVENT_STOP;
134                                         write(target->event_fd, &event,
135                                               sizeof(uint64_t));
136                                         break;
137                                 }
138                                 barloc[0] = '\0';
139                                 barloc++;
140
141                                 target->pid = atoi(log.data);
142                                 event = EVENT_PID;
143                                 write(target->event_fd, &event, sizeof(uint64_t));
144                         }
145                         continue;               // don't send to host
146                 }
147                 else if(log.type == MSG_TERMINATE)
148                 {
149                         // send stop message to main thread
150                         event = EVENT_STOP;
151                         write(target->event_fd, &event,
152                               sizeof(uint64_t));
153
154                         struct msg_data_t *msg = malloc(sizeof(*msg) + /* pid */
155                                                         sizeof(uint32_t));
156                         fill_data_msg_head(msg, NMSG_TERMINATE, 0,
157                                            sizeof(uint32_t));
158                         *(uint32_t *) msg->payload = (uint32_t) target->pid;
159                         write_to_buf(msg);
160                         free(msg);
161                         break;
162                 } else if (log.type == MSG_MSG) {
163                         // don't send to host
164                         LOGI("EXTRA MSG(%u) len=%u data='%s'\n", log.type,
165                              log.length, log.data);
166                         continue;
167                 } else if (log.type == MSG_ERROR) {
168                         // don't send to host
169                         LOGE("EXTRA MSG(%u) len=%u data='%s'\n", log.type,
170                              log.length, log.data);
171                         continue;
172                 }
173 #ifdef PRINT_TARGET_LOG
174                 else if(log.type == MSG_LOG)
175                 {
176                         switch(log.data[0])
177                         {
178                                 case '2':       // UI control creation log
179                                 case '3':       // UI event log
180                                 case '6':       // UI lifecycle log
181                                 case '7':       // screenshot log
182                                 case '8':       // scene transition log
183                                         LOGI("%dclass|%s\n", log.data[0] - '0', log.data);
184                                         break;
185                                 default:
186                                         break;
187                         }
188                 }
189                 else if(log.type == MSG_IMAGE)
190                 {
191                         LOGI("MSG_IMAGE received\n");
192                 }
193                 else    // not MSG_LOG and not MSG_IMAGE
194                 {
195                         LOGI("Extra MSG TYPE (%d|%d|%s)\n", log.type, log.length, log.data);
196                 }
197 #endif
198
199                 // do not send any message to host until MSG_PID message arrives
200                 if(unlikely(pass == 0))
201                 {
202                         while(target->initial_log == 0)
203                         {
204                                 sleep(0);
205                         }
206                 }
207                 pass = 1;
208         }
209
210         target->recv_thread = -1;
211         return NULL;
212 }
213
214 int makeRecvThread(int index)
215 {
216         if (manager.target[index].socket == -1)
217                 return -1;
218
219         if (pthread_create(&(manager.target[index].recv_thread),
220                 NULL, recvThread, &manager.target[index]) < 0)
221         {
222                 LOGE("Failed to create recv thread for socket (%d)\n",
223                                 manager.target[index].socket);
224                 return -1;
225         }
226
227         return 0;
228 }
229
230 //static
231 void* samplingThread(void* data)
232 {
233         int err, signo;
234         sigset_t waitsigmask;
235
236         LOGI("sampling thread started\n");
237
238         sigemptyset(&waitsigmask);
239         sigaddset(&waitsigmask, SIGALRM);
240         sigaddset(&waitsigmask, SIGUSR1);
241
242         while (1) {
243                 err = sigwait(&waitsigmask, &signo);
244                 if (err != 0) {
245                         LOGE("Failed to sigwait() in sampling thread\n");
246                         continue;
247                 }
248
249                 if (signo == SIGALRM) {
250                         struct system_info_t sys_info;
251                         struct msg_data_t *msg;
252
253                         if (get_system_info(&sys_info) == -1) {
254                                 LOGE("Cannot get system info\n");
255                                 //do not send sys_info because
256                                 //it is corrupted
257                                 continue;
258                         }
259
260                         msg = pack_system_info(&sys_info);
261                         if (!msg) {
262                                 LOGE("Cannot pack system info\n");
263                                 reset_system_info(&sys_info);
264                                 continue;
265                         }
266
267                         write_to_buf(msg);
268
269                         printBuf((char *)msg, MSG_DATA_HDR_LEN + msg->len);
270
271                         free_msg_data(msg);
272                         reset_system_info(&sys_info);
273                         flush_buf();
274                 }
275                 else if(signo == SIGUSR1)
276                 {
277                         LOGI("SIGUSR1 catched\n");
278                         // end this thread
279                         break;
280                 }
281                 else
282                 {
283                         // never happen
284                         LOGE("This should never happen in sampling thread\n");
285                 }
286         }
287
288         LOGI("sampling thread ended\n");
289         return NULL;
290 }
291
292 // return 0 if normal case
293 // return minus value if critical error
294 // return plus value if non-critical error
295 int samplingStart(void)
296 {
297         struct itimerval timerval;
298         time_t sec = prof_session.conf.system_trace_period / 1000;
299         suseconds_t usec = prof_session.conf.system_trace_period * 1000 %
300                 1000000;
301
302         if(manager.sampling_thread != -1)       // already started
303                 return 1;
304
305         if (check_running_status(&prof_session) == 0) {
306                 LOGI("try to start sampling when running_status is 0\n");
307                 return 1;
308         }
309
310         if(pthread_create(&(manager.sampling_thread), NULL, samplingThread, NULL) < 0)
311         {
312                 LOGE("Failed to create sampling thread\n");
313                 return -1;
314         }
315
316         timerval.it_interval.tv_sec = sec;
317         timerval.it_interval.tv_usec = usec;
318         timerval.it_value.tv_sec = sec;
319         timerval.it_value.tv_usec = usec;
320         setitimer(ITIMER_REAL, &timerval, NULL);
321
322         return 0;
323 }
324
325 int samplingStop(void)
326 {
327         if(manager.sampling_thread != -1)
328         {
329                 struct itimerval stopval;
330
331                 // stop timer
332                 stopval.it_interval.tv_sec = 0;
333                 stopval.it_interval.tv_usec = 0;
334                 stopval.it_value.tv_sec = 0;
335                 stopval.it_value.tv_usec = 0;
336                 setitimer(ITIMER_REAL, &stopval, NULL);
337
338                 pthread_kill(manager.sampling_thread, SIGUSR1);
339                 LOGI("join sampling thread started\n");
340                 pthread_join(manager.sampling_thread, NULL);
341                 LOGI("join sampling thread done\n");
342
343                 manager.sampling_thread = -1;
344         }
345
346         return 0;
347 }
348
349 static useconds_t time_diff_us(struct timeval *tv1, struct timeval *tv2)
350 {
351         return (tv1->tv_sec - tv2->tv_sec) * 1000000 +
352                 ((int)tv1->tv_usec - (int)tv2->tv_usec);
353 }
354
355 static void *replay_thread(void *arg)
356 {
357         struct replay_event_seq_t *event_seq = (struct replay_event_seq_t *)arg;
358         int i = 0;
359         useconds_t ms;
360         useconds_t prev_event_offset = 0;
361
362         struct replay_event_t * pevent = NULL;
363
364         LOGI_th_rep("replay events thread started\n");
365         if (event_seq->event_num != 0)
366         {
367                 pevent = event_seq->events;
368         }
369
370         for (i = 0; i < event_seq->event_num; i++) {
371                 useconds_t event_offset = time_diff_us(&pevent->ev.time, &event_seq->tv);
372                 if (event_offset >= prev_event_offset)
373                         ms = event_offset - prev_event_offset;
374                 else
375                         ms = 0;
376
377 #ifdef THREAD_REPLAY_DEBUG
378                 print_replay_event(pevent, i + 1, "\t");
379 #endif
380                 LOGI_th_rep("%d) sleep %d\n", i, ms);
381                 usleep(ms);
382
383                 write_input_event(pevent->id, &pevent->ev);
384
385                 prev_event_offset = event_offset;
386
387                 pevent++;
388         }
389
390         LOGI("replay events thread finished\n");
391
392         return arg;
393 }
394
395 int start_replay()
396 {
397         if (manager.replay_thread != -1) // already started
398                 return 1;
399
400         if (pthread_create(&(manager.replay_thread),
401                            NULL,
402                            replay_thread,
403                            &prof_session.replay_event_seq) < 0)
404         {
405                 LOGE("Failed to create replay thread\n");
406                 return 1;
407         }
408
409         return 0;
410 }
411
412 void stop_replay()
413 {
414         if (manager.replay_thread == -1) {
415                 LOGI("replay thread not running\n");
416                 return;
417         }
418         LOGI("stopping replay thread\n");
419         pthread_cancel(manager.replay_thread);
420         pthread_join(manager.replay_thread, NULL);
421         manager.replay_thread = -1;
422         reset_replay_event_seq(&prof_session.replay_event_seq);
423         LOGI("replay thread joined\n");
424 }