[FEATURE] Implement kernel -> user connection
[platform/core/system/swap-manager.git] / daemon / da_inst.c
1 /*
2  *  DA manager
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Cherepanov Vitaliy <v.cherepanov@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  * Contributors:
23  * - Samsung RnD Institute Russia
24  *
25  */
26
27 // TODO check memory (malloc, free)
28
29 #include <stdint.h>
30 #include <sys/types.h>
31
32 #include "da_inst.h"
33 #include "da_protocol.h"
34 #include "da_protocol_inst.h"
35 #include "debug.h"
36
37
38 struct lib_list_t *new_lib_inst_list = NULL;
39
40 uint32_t app_count = 0;
41 char *packed_app_list = NULL;
42 char *packed_lib_list = NULL;
43
44 uint32_t libs_count;
45
46 //----------------------------------- lists ----------------------------------
47
48 static int data_list_add_probe_to_hash(struct data_list_t *to, struct probe_list_t *probe)
49 {
50         // TODO add hash
51         return 0;
52 }
53
54 // create hash for lib
55 static int data_list_make_hash(struct data_list_t *what)
56 {
57         struct probe_list_t *p;
58
59         for (p = what->list; p != NULL; p = p->next)
60                 data_list_add_probe_to_hash(what, p);
61         return 0;
62 }
63
64 //------------ create - destroy
65 static struct data_list_t *new_data(void)
66 {
67         struct data_list_t *lib = malloc(sizeof(*lib));
68         lib->next = NULL;
69         lib->prev = NULL;
70         lib->hash = 0;
71         lib->size = 0;
72         lib->list = NULL;
73         return lib;
74 }
75
76 struct lib_list_t *new_lib(void)
77 {
78         struct lib_list_t *lib = (struct lib_list_t *)new_data();
79         lib->lib = malloc(sizeof(*lib->lib));
80         memset(lib->lib, 0, sizeof(*lib->lib));
81         return lib;
82 }
83
84 struct app_list_t *new_app(void)
85 {
86         struct app_list_t *app = (struct app_list_t *)new_data();
87         app->app = malloc(sizeof(*app->app));
88         memset(app->app, 0, sizeof(*app->app));
89         return app;
90 }
91
92 struct probe_list_t *new_probe(void)
93 {
94         struct probe_list_t *probe = malloc(sizeof(*probe));
95         probe->next = NULL;
96         probe->prev = NULL;
97         probe->size = 0;
98         probe->func = NULL;
99         return probe;
100 }
101
102 static void free_probe_element(struct probe_list_t *probe)
103 {
104         free(probe->func);
105         free(probe);
106 }
107
108 static void free_data_element(struct data_list_t *lib)
109 {
110         free(lib);
111 }
112
113 static void free_probe_list(struct probe_list_t *probe)
114 {
115         struct probe_list_t *next;
116         while (probe != NULL) {
117                 next = probe->next;
118                 free_probe_element(probe);
119                 probe = next;
120         }
121 }
122
123 static void free_data(struct data_list_t *lib)
124 {
125         free_probe_list(lib->list);
126         free_data_element(lib);
127 }
128
129 void free_data_list(struct data_list_t **data)
130 {
131         while (*data != NULL) {
132                 struct data_list_t *next = (*data)->next;
133                 free_data(*data);
134                 *data = next;
135         }
136 }
137
138 //------------- add - remove
139 int data_list_append(struct data_list_t **to, struct data_list_t *from)
140 {
141         struct data_list_t *p = NULL;
142         if (*to == NULL) {
143                 // empty list
144                 *to = from;
145         } else {
146                 p = *to;
147                 *to = from;
148                 from->next = (void *)p;
149                 p->prev = (void *)from;
150         }
151         return 0;
152 }
153
154
155 static int data_list_append_probes_hash(struct data_list_t *to, struct data_list_t *from)
156 {
157         struct probe_list_t *p = from->list;
158         struct probe_list_t *last = p;
159
160         to->size += p->size;
161         to->func_num += from->func_num;
162         for (p = from->list; p != NULL; p = p->next) {
163                 data_list_add_probe_to_hash(to, p);
164                 last = p;
165         }
166
167         last->next = to->list;
168         to->list->prev = last;
169         to->list = from->list;
170
171         return 1;
172 }
173
174 int probe_list_append(struct data_list_t *to, struct probe_list_t *from)
175 {
176         struct probe_list_t **list = &(to->list);
177         struct probe_list_t *p = NULL;
178         uint32_t num = 0;
179         if (*list == NULL) {
180                 // empty list
181                 *list = from;
182         } else {
183                 p = *list;
184                 *list = from;
185                 from->next = (void *)p;
186                 p->prev = (void *)from;
187         }
188         to->size += from->size;
189
190         num = 0;
191         for (p = from; p != NULL; p = p->next)
192                 num++;
193         to->func_num += num;
194         return 0;
195 }
196
197 static struct probe_list_t *probe_list_rm_element(struct data_list_t *list, struct probe_list_t *element)
198 {
199         struct probe_list_t *prev = element->prev;
200         struct probe_list_t *next = element->next;
201         if (element != NULL) {
202                 if (prev != NULL)
203                         // prev != null, next == null
204                         // prev != null, next != null
205                         prev->next = next;
206                 else
207                         // prev == null, next == null
208                         // prev == null, next != null
209                         list->list = next;
210
211                 if (next != NULL)
212                         next->prev = prev;
213
214                 list->size -= element->size;
215         }
216
217         list->func_num--;
218         free_probe_element(element);
219         return next;
220 }
221
222 static struct data_list_t *data_list_unlink_data(struct data_list_t **list, struct data_list_t *element)
223 {
224         struct data_list_t *prev = element->prev;
225         struct data_list_t *next = element->next;
226         if (element != NULL) {
227                 if (prev != NULL)
228                         // prev != null, next == null
229                         // prev != null, next != null
230                         prev->next = next;
231                 else
232                         // prev == null, next == null
233                         // prev == null, next != null
234                         *list = next;
235
236                 if (next != NULL)
237                         next->prev = (struct lib_list_t *)prev;
238
239         }
240         element->prev = NULL;
241         element->next = NULL;
242
243         return next;
244 }
245
246 static struct data_list_t *data_list_rm_data(struct data_list_t **list, struct data_list_t *element)
247 {
248         struct data_list_t *next = NULL;
249
250         next = data_list_unlink_data(list, element);
251         free_data_element(element);
252
253         return next;
254 }
255
256 // find
257 static struct data_list_t *data_list_find_data(struct data_list_t *whered, struct data_list_t *whatd, cmp_data_f cmp)
258 {
259         struct data_list_t *where;
260         struct data_list_t *what = whatd;
261         for (where = whered; where != NULL; where = where->next) {
262                 if (where->hash == what->hash) {
263                         if (cmp(where, what))
264                                 return where;
265                 }
266         }
267         return NULL;
268 }
269
270 static struct probe_list_t *find_probe(struct data_list_t *where, struct probe_list_t *probe)
271 {
272         struct probe_list_t *p ;
273         for (p = where->list; p != NULL; p = p->next)
274                 if (p->size == probe->size)
275                         if (p->func->func_addr == probe->func->func_addr)
276                                 if (strcmp(p->func->args, probe->func->args) == 0)
277                                         break;
278
279         return p;
280 }
281
282 // "from" will be destroyed after this call
283 static int data_list_move_with_hash(struct data_list_t **to, struct data_list_t **from, cmp_data_f cmp)
284 {
285
286         struct data_list_t *p = *from;
287         struct data_list_t *next = NULL;
288         struct data_list_t *sch = NULL;
289         while (p != NULL) {
290                 sch = data_list_find_data(*to, p, cmp);
291                 next = data_list_unlink_data(from, p);
292                 if (sch == NULL) {
293                         data_list_make_hash(p);
294                         data_list_append(to, p);
295                 } else {
296                         data_list_append_probes_hash(sch, p);
297                 }
298                 p = next;
299         }
300         return 1;
301 }
302
303 //---------------------------- collisions resolve ------------------------------
304
305 static int cmp_libs(struct data_list_t *el_1, struct data_list_t *el_2)
306 {
307         return (strcmp(
308                         ((struct lib_list_t *)el_1)->lib->bin_path,
309                         ((struct lib_list_t *)el_2)->lib->bin_path
310                         ) == 0);
311 }
312
313 ///////////////////////////////////////////////////////////////////////////
314 // function removes from new list all probes which are already installed
315 //
316 // cur - current state (lib list with probes)
317 // new - additional probes which were received with MSG_SWAP_INST_ADD msg
318 //       (lib list with probes)
319 // this function removes all probes which are present in cur and new list from
320 // new list so after this function call in new list will be only probes which are
321 // not present in cur list
322 static int resolve_collisions_for_add_msg(struct lib_list_t **cur, struct lib_list_t **new)
323 {
324         struct data_list_t *p = (struct data_list_t *)*new;
325         struct data_list_t *sch = NULL;
326
327         struct probe_list_t *pr = NULL;
328         struct probe_list_t *next_pr = NULL;
329
330         // remove collisions from list "new"
331         while (p != NULL) {
332                 sch = data_list_find_data((struct data_list_t *)*cur, p, cmp_libs);
333                 if (sch == NULL) {
334                         // lib not found in cur config
335                 } else {
336                         // lib found in cur config so resolve collisions
337                         pr = p->list;
338                         while (pr != NULL) {
339                                 // remove collisions
340                                 if (find_probe(sch, pr) != NULL) {
341                                         // probe already exist
342                                         // rm from new config
343                                         next_pr = probe_list_rm_element(p, pr);
344                                         pr = next_pr;
345                                 } else {
346                                         pr = pr->next;
347                                 }
348                         }
349
350                         // rm lib if it is empty
351                         if (p->list == NULL) {
352                                 p = data_list_rm_data((struct data_list_t **)new, p);
353                                 continue;
354                         }
355                 }
356                 p = p->next;
357         }
358         return 1;
359 }
360
361 ///////////////////////////////////////////////////////////////////////////
362 // function removes from cur list all probes which are in list "new"
363 //         and removes from "new" all probes which are not instaled
364 //
365 // cur - current state (lib list with probes)
366 // new - list for probes remove which were received with MSG_SWAP_INST_REMOVE msg
367 //
368 // this function removes all probes which are present in cur and new list from
369 // cur list and removes all probes which are present in new but not present in
370 // cur list so after this function call in new list will be only probes which are
371 // present in cur list
372 static int resolve_collisions_for_rm_msg(struct lib_list_t **cur, struct lib_list_t **new)
373 {
374         struct data_list_t *p = (struct data_list_t *)*new;
375         struct data_list_t *next_l = NULL;
376         struct data_list_t *sch = NULL;
377
378         struct probe_list_t *pr = NULL;
379         struct probe_list_t *next_pr = NULL;
380         struct probe_list_t *tmp = NULL;
381
382         // remove collisions from list "new"
383         while (p != NULL) {
384                 sch = data_list_find_data((struct data_list_t *)*cur, p, cmp_libs);
385                 if (sch == NULL) {
386                         //lib not found so no probes remove
387                         next_l = data_list_rm_data((struct data_list_t **)new, p);
388                 } else {
389                         //lib found so we need remove collisions
390                         pr = p->list;
391                         if (pr == NULL) {
392                                 // if rm probe list is empty that is mean we need
393                                 // to remove all probes on this lib
394                                 data_list_unlink_data((struct data_list_t **)cur, sch);
395                                 data_list_append((struct data_list_t **)new, sch);
396                                 next_l = data_list_rm_data((struct data_list_t **)cur, p);
397                         } else {
398                                 // lib is not empty so merge
399                                 while (pr != NULL) {
400                                         // remove collisions
401                                         if ((tmp = find_probe(sch, pr)) != NULL) {
402                                                 // probe found so remove probe
403                                                 // from cur state
404                                                 probe_list_rm_element(sch, tmp);
405                                                 pr = pr->next;
406                                         } else {
407                                                 // probe no found so remove it
408                                                 // from new state
409                                                 next_pr = probe_list_rm_element(p, pr);
410                                                 pr = next_pr;
411                                         }
412                                 }
413                                 // rm lib if it is empty
414                                 if (sch->list == NULL) {
415                                         data_list_rm_data((struct data_list_t **)cur, sch);
416                                 }
417                                 next_l = p->next;
418                         }
419                 }
420                 p = next_l;
421         }
422         return 1;
423 }
424
425 //--------------------------------------pack ----------------------------------
426
427 static char *pack_lib_head_to_array(char *to, void *data)
428 {
429         struct us_lib_inst_t *lib = data;
430         pack_str(to, lib->bin_path);
431         return to;
432 }
433
434 static char *pack_app_head_to_array(char *to, void *data)
435 {
436         struct app_info_t *app = data;
437         pack_int32(to, app->app_type);
438         pack_str(to, app->app_id);
439         pack_str(to, app->exe_path);
440         return to;
441 }
442
443 static char *pack_data_to_array(struct data_list_t *data, char *to, pack_head_t pack_head)
444 {
445         struct probe_list_t *p;
446
447         to = pack_head(to, data->data);
448         pack_int32(to, data->func_num);
449         for (p = data->list; p != NULL; p = p->next) {
450                 memcpy(to, p->func, p->size);
451                 to += p->size;
452         }
453         return to;
454 }
455
456 static char *pack_data_list_to_array(struct data_list_t *list, uint32_t *len, uint32_t *count, pack_head_t pack)
457 {
458         char *res = NULL;
459         char *to = NULL;
460         uint32_t size = 0;
461         uint32_t cnt = 0;
462         struct data_list_t *p = list;
463
464         for (p = list; p != NULL; p = p->next) {
465                 size += p->size;
466                 cnt++;
467         }
468
469         size += sizeof(uint32_t);
470         *len = size;
471         *count = cnt;
472
473         if (size != 0) {
474                 res = malloc(size);
475                 to = res;
476                 if (to != NULL) {
477                         memset(to, '*', size);
478                         pack_int32(to, cnt);
479                         for (p = list; p != NULL; p = p->next)
480                                 to = pack_data_to_array(p, to, pack);
481                 } else {
482                         LOGE("can not malloc buffer for data list packing\n");
483                 }
484         }
485         return res;
486 }
487
488 static char *pack_lib_list_to_array(struct lib_list_t *list, uint32_t *size, uint32_t *count)
489 {
490         return pack_data_list_to_array((struct data_list_t *)list, size,
491                                         count, pack_lib_head_to_array);
492 }
493
494 static char *pack_app_list_to_array(struct app_list_t *list, uint32_t *size, uint32_t *count)
495 {
496         return pack_data_list_to_array((struct data_list_t *)list, size,
497                                         count,  pack_app_head_to_array);
498 }
499
500 static int generate_msg(struct msg_t **msg, struct lib_list_t *lib_list, struct app_list_t *app_list)
501 {
502         uint32_t i,
503                  size = 0,
504                  libs_size = 0,
505                  apps_size = 0,
506                  libs_count = 0,
507                  apps_count = 0;
508         char     *p = NULL;
509
510         packed_lib_list = pack_lib_list_to_array(lib_list, &libs_size, &libs_count);
511         // print_buf(packed_lib_list, libs_size, "LIBS");
512
513         packed_app_list = pack_app_list_to_array(app_list, &apps_size, &apps_count);
514         // print_buf(packed_app_list, apps_size, "APPS");
515
516         size = apps_count * libs_size + apps_size;
517
518         LOGI("size = %d, apps= %d, libs = %d\n", size, apps_count, libs_count);
519
520         // add header size
521         *msg = malloc(size + sizeof(**msg));
522         memset(*msg, '*', size);
523
524         p = (char *)*msg;
525         pack_int32(p, 0);               // msg id
526         pack_int32(p, size);            // payload size
527         pack_int32(p, apps_count);
528
529         struct app_list_t *app = app_list;
530         char *app_p = packed_app_list + sizeof(((struct user_space_inst_t *)0)->app_num);
531
532         for (i = 0; i < apps_count; i++) {
533                 memcpy(p, app_p, app->size);
534                 p += app->size;
535                 memcpy(p, packed_lib_list, libs_size);
536                 p += libs_size;
537
538                 app_p += app->size;
539                 app = app->next;
540         }
541
542         // print_buf((char *)*msg, size, "ANSWER");
543         return 1;
544 }
545
546 //-----------------------------------------------------------------------------
547 struct app_info_t *app_info_get_first(struct app_list_t **app_list)
548 {
549         *app_list = prof_session.user_space_inst.app_inst_list;
550         if (*app_list == NULL) {
551                 return NULL;
552         }
553
554         return (*app_list)->app;
555 }
556
557 struct app_info_t *app_info_get_next(struct app_list_t **app_list)
558 {
559         if (*app_list == NULL)
560                 return NULL;
561
562         if ((*app_list = (*app_list)->next) == NULL)
563                 return NULL;
564
565         return (*app_list)->app;
566 }
567
568 //-----------------------------------------------------------------------------
569 int msg_start(struct msg_buf_t *data, struct user_space_inst_t *us_inst,
570               struct msg_t **msg, enum ErrorCode *err)
571 {
572         char *p = NULL;
573         *msg = NULL;
574         if (!parse_app_inst_list(data, &us_inst->app_num, &us_inst->app_inst_list)) {
575                 *err = ERR_WRONG_MESSAGE_FORMAT;
576                 LOGE("parse app inst\n");
577                 return 1;
578         }
579
580         generate_msg(msg, us_inst->lib_inst_list, us_inst->app_inst_list);
581
582         if (*msg != NULL) {
583                 p = (char *)*msg;
584                 pack_int32(p, NMSG_START);
585         } else {
586                 *err = ERR_CANNOT_START_PROFILING;
587                 return 1;
588         }
589         return 0;
590 }
591
592 int msg_swap_inst_add(struct msg_buf_t *data, struct user_space_inst_t *us_inst,
593                       struct msg_t **msg, enum ErrorCode *err)
594 {
595         uint32_t lib_num = 0;
596         char *p = NULL;
597
598         *err = ERR_UNKNOWN;
599
600         if (!parse_lib_inst_list(data, &lib_num, &us_inst->lib_inst_list)) {
601                 *err = ERR_WRONG_MESSAGE_FORMAT;
602                 LOGE("parse lib inst list fail\n");
603                 return 1;
604         }
605         // rm probes from new if its presents in cur
606         if (!resolve_collisions_for_add_msg(&us_inst->lib_inst_list, &new_lib_inst_list)) {
607                 LOGE("resolve collision\n");
608                 return 1;
609         };
610
611         // generate msg to send
612         if (us_inst->app_inst_list != NULL) {
613                 generate_msg(msg, new_lib_inst_list, us_inst->app_inst_list);
614                 p = (char *)*msg;
615                 pack_int32(p, NMSG_SWAP_INST_ADD);
616         }
617         // apply changes to cur state
618         if (!data_list_move_with_hash(
619                 (struct data_list_t **)&us_inst->lib_inst_list,
620                 (struct data_list_t **)&new_lib_inst_list,
621                 cmp_libs))
622         {
623                 LOGE("data move\n");
624                 return 1;
625         };
626
627         // free new_list
628         free_data_list((struct data_list_t **)&new_lib_inst_list);
629         new_lib_inst_list = NULL;
630         *err = ERR_NO;
631         return 0;
632 }
633
634 int msg_swap_inst_remove(struct msg_buf_t *data, struct user_space_inst_t *us_inst,
635                          struct msg_t **msg, enum ErrorCode *err)
636 {
637         uint32_t lib_num = 0;
638         char *p = NULL;
639         *err = ERR_UNKNOWN;
640
641         if (!parse_lib_inst_list(data, &lib_num, &new_lib_inst_list)) {
642                 *err = ERR_WRONG_MESSAGE_FORMAT;
643                 LOGE("parse lib inst\n");
644                 return 1;
645         }
646
647         if (!resolve_collisions_for_rm_msg(&us_inst->lib_inst_list, &new_lib_inst_list)) {
648                 LOGE("resolve collisions\n");
649                 return 1;
650         }
651
652         if (us_inst->app_inst_list != NULL) {
653                 if (!generate_msg(msg, new_lib_inst_list, us_inst->app_inst_list)) {
654                         LOGE("generate msg\n");
655                         return 1;
656                 }
657                 p = (char *)*msg;
658                 pack_int32(p, NMSG_SWAP_INST_ADD);
659         }
660
661         free_data_list((struct data_list_t **)&new_lib_inst_list);
662         new_lib_inst_list = NULL;
663         *err = ERR_NO;
664         return 0;
665 }