tizen 2.3.1 release
[kernel/api/system-resource.git] / src / proc-stat / proc-stat.c
1 /*
2  * resourced
3  *
4  * Library for getting process statistics
5  *
6  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28 #include <linux/limits.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <fcntl.h>
34 #include <dirent.h>
35 #include <ctype.h>
36 #include <unistd.h>
37
38 #include "macro.h"
39 #include "proc_stat.h"
40 #include "trace.h"
41 #include "proc-noti.h"
42 #include "const.h"
43
44 #define PROC_STAT_PATH "/proc/%d/stat"
45 #define PROC_STATM_PATH "/proc/%d/statm"
46 #define PROC_CMDLINE_PATH "/proc/%d/cmdline"
47
48 #ifndef TEST_IN_X86
49 #include <assert.h>
50 #else
51 #define assert(x) \
52 do { \
53         if (!(x)) { \
54                 printf("assertion %s %d\n", __FILE__ , __LINE__); \
55                 exit(-1); \
56         } \
57 } while (0)
58 #endif
59
60 API bool proc_stat_get_cpu_time_by_pid(pid_t pid, unsigned long *utime,
61                                        unsigned long *stime)
62 {
63         char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
64         FILE *fp;
65
66         assert(utime != NULL);
67         assert(stime != NULL);
68
69         snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
70         fp = fopen(proc_path, "r");
71         if (fp == NULL)
72                 return false;
73
74         if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
75                 fclose(fp);
76                 return false;
77         }
78
79         if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
80                 fclose(fp);
81                 return false;
82         }
83
84         fclose(fp);
85
86         return true;
87 }
88
89
90 API bool proc_stat_get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
91 {
92         FILE *fp;
93         char proc_path[sizeof(PROC_STATM_PATH) + MAX_DEC_SIZE(int)] = {0};
94
95         snprintf(proc_path, sizeof(proc_path), PROC_STATM_PATH, pid);
96         fp = fopen(proc_path, "r");
97         if (fp == NULL)
98                 return false;
99
100         if (fscanf(fp, "%*s %d", rss) < 1) {
101                 fclose(fp);
102                 return false;
103         }
104
105         fclose(fp);
106
107         /* convert page to Kb */
108         *rss *= 4;
109         return true;
110 }
111
112
113 static int get_mem_size(char *buffer, const char *const items[], const int items_len[], const int items_cnt, unsigned int mem_size[])
114 {
115         char *p = buffer;
116         int num_found = 0;
117
118         while (*p && num_found < items_cnt) {
119                 int i = 0;
120                 while (i < items_cnt) {
121                         if (strncmp(p, items[i], items_len[i] - 1) == 0) {
122                                 /* the format of line is like this "MemTotal:             745696 kB" */
123                                 /* when it finds a item, skip the name of item */
124                                 p += items_len[i];
125
126                                 /* skip white space */
127                                 while (*p == ' ')
128                                         ++p;
129
130                                 char *num = p;
131
132                                 /* go to the immediate next of numerical value */
133                                 while (*p >= '0' && *p <= '9')
134                                         ++p;
135
136                                 /* at this time, [num,p) is the value of item */
137
138                                 /* insert null to p to parse [num,p] by atoi() */
139                                 if (*p != 0) {
140                                         *p = 0;
141                                         ++p;
142
143                                         /* when it is the end of buffer, to avoid out of buffer */
144                                         if (*p == 0)
145                                                 --p;
146                                 }
147                                 mem_size[i] = atoi(num);
148                                 num_found++;
149                                 break;
150                         }
151                         ++i;
152                 }
153                 ++p;
154         }
155
156         return num_found;
157 }
158
159
160 API bool proc_stat_get_total_mem_size(unsigned int *total_mem)
161 {
162         int fd = 0;
163         int len = 0;
164         char *buffer = NULL;
165         const int buffer_size = 4096;
166         static const char *const items[] = { "MemTotal:" };
167         static const int items_len[] = {sizeof("MemTotal:") };
168         unsigned int mem_size[1];
169         int num_found;
170
171         assert(total_mem != NULL);
172
173         fd = open("/proc/meminfo", O_RDONLY);
174         if (fd < 0)
175                 return false;
176
177         buffer = malloc(buffer_size);
178         assert(buffer != NULL);
179
180         len = read(fd, buffer, buffer_size - 1);
181         close(fd);
182
183         if (len < 0) {
184                 free(buffer);
185                 return false;
186         }
187
188         buffer[len] = 0;
189
190         /* to get the best search performance, the order of items should refelect the order of /proc/meminfo */
191         num_found = get_mem_size(buffer, items, items_len, 1 , mem_size);
192
193         free(buffer);
194
195         if (num_found < 1)
196                 return false;
197
198         /* total_mem = "MemTotal" */
199         *total_mem = mem_size[0] / 1024;
200
201         return true;
202 }
203
204
205 API bool proc_stat_get_free_mem_size(unsigned int *free_mem)
206 {
207         int fd = 0;
208         char *buffer = NULL;
209         const int buffer_size = 4096;
210         int len = 0;
211         static const char *const items[] = { "MemFree:", "Buffers:", "Cached:", "SwapCached:", "Shmem:" };
212         static const int items_len[] = { sizeof("MemFree:"), sizeof("Buffers:"), sizeof("Cached:"),
213                                                           sizeof("SwapCached:"), sizeof("Shmem:") };
214         static const int items_cnt = ARRAY_SIZE(items);
215         unsigned int mem_size[items_cnt];
216         int num_found;
217
218         assert(free_mem != NULL);
219
220         fd = open("/proc/meminfo", O_RDONLY);
221
222         if (fd < 0)
223                 return false;
224
225         buffer = malloc(buffer_size);
226         assert(buffer != NULL);
227
228         len = read(fd, buffer, buffer_size - 1);
229         close(fd);
230
231         if (len < 0) {
232                 free(buffer);
233                 return false;
234         }
235
236         buffer[len] = 0;
237
238
239         /* to get the best search performance, the order of items should refelect the order of /proc/meminfo */
240         num_found = get_mem_size(buffer, items, items_len, items_cnt, mem_size);
241
242         free(buffer);
243
244         if (num_found < items_cnt)
245                 return false;
246
247         /* free_mem = "MemFree" + "Buffers" + "Cached" + "SwapCache" - "Shmem" */
248         *free_mem = (mem_size[0] + mem_size[1] + mem_size[2] + mem_size[3] - mem_size[4]) / 1024;
249
250         return true;
251 }
252
253 static bool get_proc_cmdline(pid_t pid, char *cmdline)
254 {
255         assert(cmdline != NULL);
256
257         char buf[PATH_MAX];
258         char cmdline_path[sizeof(PROC_CMDLINE_PATH) + MAX_DEC_SIZE(int)] = {0};
259         char *filename;
260         FILE *fp;
261
262         snprintf(cmdline_path, sizeof(cmdline_path), PROC_CMDLINE_PATH, pid);
263         fp = fopen(cmdline_path, "r");
264         if (fp == NULL)
265                 return false;
266
267         if (fscanf(fp, "%s", buf) < 1) {
268                 fclose(fp);
269                 return false;
270         }
271         fclose(fp);
272
273
274         filename = strrchr(buf, '/');
275         if (filename == NULL)
276                 filename = buf;
277         else
278                 filename = filename + 1;
279
280         strncpy(cmdline, filename, NAME_MAX-1);
281
282         return true;
283 }
284
285 static bool get_proc_filename(pid_t pid, char *process_name)
286 {
287         FILE *fp;
288         char buf[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
289         char filename[PATH_MAX];
290
291         assert(process_name != NULL);
292
293         snprintf(buf, sizeof(buf), PROC_STAT_PATH, pid);
294         fp = fopen(buf, "r");
295
296         if (fp == NULL)
297                 return false;
298
299         if (fscanf(fp, "%*s (%[^)]", filename) < 1) {
300                 fclose(fp);
301                 return false;
302         }
303
304         strncpy(process_name, filename, NAME_MAX-1);
305         fclose(fp);
306
307         return true;
308 }
309
310 API bool proc_stat_get_name_by_pid(pid_t pid, char *name)
311 {
312
313         assert(name != NULL);
314
315         if (get_proc_cmdline(pid, name))
316                 return true;
317         else if (get_proc_filename(pid, name))
318                 return true;
319
320         return false;
321 }
322
323
324 static void diff_system_time(proc_stat_system_time *st_diff, proc_stat_system_time *st_a, proc_stat_system_time *st_b)
325 {
326         assert(st_diff != NULL);
327         assert(st_a != NULL);
328         assert(st_b != NULL);
329
330         st_diff->total_time = st_a->total_time - st_b->total_time;
331         st_diff->user_time = st_a->user_time - st_b->user_time;
332         st_diff->nice_time = st_a->nice_time - st_b->nice_time;
333         st_diff->system_time = st_a->system_time - st_b->system_time;
334         st_diff->idle_time = st_a->idle_time - st_b->idle_time;
335         st_diff->iowait_time = st_a->iowait_time - st_b->iowait_time;
336         st_diff->irq_time = st_a->irq_time - st_b->irq_time;
337         st_diff->softirq_time = st_a->softirq_time - st_b->softirq_time;
338 }
339
340 static bool get_system_time(proc_stat_system_time *st)
341 {
342         FILE *fp;
343
344         assert(st != NULL);
345
346         fp = fopen("/proc/stat", "r");
347         if (fp == NULL)
348                 return false;
349
350         if (fscanf(fp, "%*s %lld %lld %lld %lld %lld %lld %lld",
351                 &st->user_time, &st->nice_time, &st->system_time, &st->idle_time,
352                 &st->iowait_time, &st->irq_time, &st->softirq_time) < 1) {
353                 fclose(fp);
354                 return false;
355         }
356
357         fclose(fp);
358
359         st->total_time = st->user_time + st->nice_time + st->system_time + st->idle_time
360                                 + st->iowait_time + st->irq_time + st->softirq_time;
361
362         return true;
363 }
364
365
366
367 API bool proc_stat_get_system_time_diff(proc_stat_system_time *st_diff)
368 {
369         static proc_stat_system_time prev_st;
370         proc_stat_system_time cur_st;
371
372         assert(st_diff != NULL);
373
374         get_system_time(&cur_st);
375
376         if (prev_st.total_time == 0) {
377                 memset(st_diff, 0, sizeof(proc_stat_system_time));
378                 prev_st = cur_st;
379                 return false;
380         }
381
382         diff_system_time(st_diff, &cur_st, &prev_st);
383         prev_st = cur_st;
384
385         return (bool) (st_diff->total_time);
386 }
387
388
389 static int comapre_pid(const pid_t *pid_a, const pid_t *pid_b)
390 {
391         assert(pid_a != NULL);
392         assert(pid_b != NULL);
393
394         /* the process which has smaller number of pid is ordered ahead */
395         return (*pid_a - *pid_b);
396 }
397
398 /**
399  * @brief Get pids under /proc file system
400  *
401  * @param pids the pointer of GArray to store pids
402  * @return  true on success, false on failure.
403  *
404  * This function fills Garray instance with pids under /proc file system.
405  */
406
407 static bool get_pids(GArray *pids)
408 {
409         DIR *dirp;
410         struct dirent entry;
411         struct dirent *result;
412         int ret;
413
414         assert(pids != NULL);
415
416         dirp = opendir("/proc");
417
418         if (dirp == NULL)
419                 return false;
420
421         while (!(ret = readdir_r(dirp, &entry, &result)) && result != NULL) {
422                 const char *p = entry.d_name;
423                 char *end;
424                 pid_t pid;
425
426                 while (*p) {
427                         if (*p < '0' || *p > '9')
428                                 break;
429                         p++;
430                 }
431
432                 if (*p != 0)
433                         continue;
434
435                 pid = strtol(entry.d_name, &end, 10);
436
437                 g_array_append_val(pids, pid);
438         }
439         closedir(dirp);
440
441         if (ret)
442                 return false;
443
444         g_array_sort(pids, (GCompareFunc)comapre_pid);
445
446         return true;
447 }
448
449 API bool proc_stat_get_pids(pid_t **pids, int *cnt)
450 {
451         unsigned int i;
452         GArray *garray = NULL;
453
454         assert(pids != NULL);
455         assert(cnt != NULL);
456
457         garray = g_array_new(false, false, sizeof(pid_t));
458         g_return_val_if_fail(garray, false);
459
460         if (get_pids(garray) == false) {
461                 /* g_array_free is resistant to input NULL */
462                 g_array_free(garray, true);
463                 return false;
464         }
465
466         *pids = malloc(sizeof(pid_t) * garray->len);
467         assert(*pids != NULL);
468
469         *cnt = garray->len;
470
471         for (i = 0 ; i < garray->len; ++i)
472                 (*pids)[i] = g_array_index(garray, pid_t, i);
473
474         g_array_free(garray, true);
475
476         return true;
477 }
478
479
480 /**
481  * @brief Fill proc_infos with proc_stat_process_info instances which have process statistics , specially time difference each process spent in user mode and system mode between two consecutive its calls
482  *
483  * @param pids GArray instance which have current pids under /proc file system
484  * @param proc_infos the pointer of GArray instance to be filled with proc_stat_process_info instances which are matched with each pid in pids.
485  * @param terminated_proc_infos the pointer of GArray instance to be filled with proc_stat_process_info instances which were terminated between two consecutive its calls
486                   ,pass NULL if if this information is not necessary
487  * @return nothing
488  *
489  * This function fills proc_infos with proc_stat_process_info instances which have process statistics , specially time difference each process spent in user mode and system mode between two consecutive its calls
490  *
491  */
492
493 static void update_proc_infos(GArray *pids, GArray *proc_infos,
494                                                 GArray *terminated_proc_infos)
495 {
496         /* when this function is called first, we don't have basis
497         *  for time interval, so it is not valid.
498         */
499         static bool first = true;
500
501         unsigned int pids_cnt = 0;
502         unsigned int cur_pi_idx = 0;
503         proc_stat_process_info *pi = NULL;
504
505         unsigned int i;
506
507         assert(pids != NULL);
508         assert(proc_infos != NULL);
509
510         pids_cnt = pids->len;
511
512         /* with current pids, update proc_infos */
513         for (i = 0 ; i < pids_cnt; ++i) {
514                 unsigned long utime, stime;
515
516                 if (cur_pi_idx < proc_infos->len)
517                         pi = &g_array_index(proc_infos, proc_stat_process_info, cur_pi_idx);
518                 else
519                 /* current pid is out of proc_infos, so it is new pid. */
520                         pi = NULL;
521
522                 assert(i < pids->len);
523                 pid_t pid = g_array_index(pids, pid_t, i);
524
525                 if ((pi != NULL) && (pi->pid == pid)) {
526                         /* current pid is matched with proc_infos[curPsIdex],
527                         *  so update proc_infos[curPsIdex]
528                         */
529                         ++cur_pi_idx;
530
531                         pi->fresh = false; /* it is not new process */
532                         /* by now, we don't know whether it is valid or not,
533                         *  so mark it as invalid by default.
534                         */
535                         pi->valid = false;
536
537                         if (!(proc_stat_get_cpu_time_by_pid(pid, &utime, &stime) && proc_stat_get_mem_usage_by_pid(pid, &(pi->rss))))
538                                 continue;
539
540                         if ((pi->utime_prev == utime) && (pi->stime_prev == stime)) {
541                                 /* There is no diff in execution time, mark it as inactive. */
542                                 pi->utime_diff = 0;
543                                 pi->stime_diff = 0;
544                                 pi->active = false;
545                                 continue;
546                         } else {
547                                 pi->active = true; /* mark it as active */
548                         }
549                         /* update time related fields */
550                         pi->utime_diff = (utime - pi->utime_prev);
551                         pi->stime_diff = (stime - pi->stime_prev);
552                         pi->utime_prev = utime;
553                         pi->stime_prev = stime;
554
555                         pi->valid = true; /* mark it as valid */
556                 } else if ((pi == NULL) || (pi->pid > pid)) {
557                         /* in case of new process */
558                         proc_stat_process_info new_pi;
559
560                         new_pi.pid = pid;
561
562                         if (!(proc_stat_get_name_by_pid(pid, new_pi.name) && proc_stat_get_cpu_time_by_pid(pid, &utime, &stime) && proc_stat_get_mem_usage_by_pid(pid, &new_pi.rss)))
563                                 continue; /* in case of not getting information of current pid, skip it */
564
565                         new_pi.fresh = true; /* mark it as new (process) */
566                         new_pi.utime_prev = utime;
567                         new_pi.stime_prev = stime;
568                         new_pi.utime_diff = utime;
569                         new_pi.stime_diff = stime;
570
571                         if (first == false)
572                                 /* This process is created after the first call of update_proc_infos, so we know execution time of it.
573                                 *  Mark it as valid.
574                                 */
575                                 new_pi.valid = true;
576                         else
577                                 new_pi.valid = false;
578
579                         /* add it to proc_infos */
580                         g_array_insert_val(proc_infos, cur_pi_idx , new_pi);
581                         ++cur_pi_idx;
582                 } else {
583                         if (terminated_proc_infos != NULL) {
584                                 proc_stat_process_info terminated_pi;
585                                 terminated_pi = *pi;
586                                 g_array_append_val(terminated_proc_infos, terminated_pi);
587                         }
588
589                         /* in case of the process terminated, remove it from proc_infos */
590                         assert(cur_pi_idx < proc_infos->len);
591                         g_array_remove_index(proc_infos, cur_pi_idx);
592                         /* current pid should be compared again, so decrease loop count */
593                         --i;
594                 }
595
596         }
597
598         /* in case of the process terminated, remove it from proc_infos */
599         while (cur_pi_idx < proc_infos->len) {
600                 if (terminated_proc_infos != NULL) {
601                         proc_stat_process_info terminated_pi;
602
603                         assert(cur_pi_idx < proc_infos->len);
604                         terminated_pi = g_array_index(proc_infos, proc_stat_process_info, cur_pi_idx);
605                         g_array_append_val(terminated_proc_infos, terminated_pi);
606                 }
607
608                 assert(cur_pi_idx < proc_infos->len);
609                 g_array_remove_index(proc_infos, cur_pi_idx);
610         }
611
612         first = false;
613 }
614
615
616
617 static int compare_proc_info(const proc_stat_process_info *proc_info_a, const proc_stat_process_info *proc_info_b)
618 {
619         /*
620         * Firstly, long execution time process is ordered  ahead
621         * Secondly, newly created process is ordered ahead
622         */
623         unsigned long exec_time_a, exec_time_b;
624
625         assert(proc_info_a != NULL);
626         assert(proc_info_b != NULL);
627
628         exec_time_a = proc_info_a->utime_diff + proc_info_a->stime_diff;
629         exec_time_b = proc_info_b->utime_diff + proc_info_b->stime_diff;
630
631         if (exec_time_a != exec_time_b)
632                 return (exec_time_b - exec_time_a);
633
634         if (proc_info_a->fresh != proc_info_b->fresh)
635                 return ((int)(proc_info_b->fresh) - (int)(proc_info_a->fresh));
636
637         return 0;
638
639 }
640
641
642 /**
643  * @brief Extract valid proc_stat_process_info instances from proc_infos and fill valid_proc_infos with these instances
644  *
645  * @param proc_infos from which source to extract valid proc_stat_process_info instances
646  * @param valid_proc_infos GArray instance to be filled with valid proc_stat_process_info instances
647  * @param total_valid_proc_time to get the sum of the time spent by all valid proc_stat_process_info instance, pass NULL if if this information is not necessary
648  * @return  nothing
649  *
650  * This function extracts valid proc_stat_process_info instances from proc_infos and fills valid_proc_infos with these instances
651  */
652 static void pick_valid_proc_infos(GArray *proc_infos, GArray *valid_proc_infos, unsigned long *total_valid_proc_time)
653 {
654         unsigned int i;
655         proc_stat_process_info pi;
656
657         assert(valid_proc_infos != NULL);
658
659         if (total_valid_proc_time != NULL)
660                 *total_valid_proc_time = 0;
661
662         for (i = 0; i < proc_infos->len ; ++i) {
663                 assert(i < proc_infos->len);
664                 pi = g_array_index(proc_infos, proc_stat_process_info, i);
665
666                 if (pi.valid) {
667                         g_array_append_val(valid_proc_infos, pi);
668
669                         if (total_valid_proc_time != NULL)
670                                 *total_valid_proc_time += (pi.utime_diff+pi.stime_diff);
671                 }
672         }
673
674         g_array_sort(valid_proc_infos, (GCompareFunc)compare_proc_info);
675 }
676
677
678 static GArray *g_pids = NULL;
679 static GArray *proc_infos = NULL;
680
681 API void proc_stat_init(void)
682 {
683         g_pids = g_array_new(false, false, sizeof(pid_t));
684         proc_infos = g_array_new(false, false, sizeof(proc_stat_process_info));
685 }
686
687 API bool proc_stat_get_process_info(GArray *valid_proc_infos,
688                                     GArray *terminated_proc_infos,
689                                     unsigned long *total_valid_proc_time)
690 {
691         assert(valid_proc_infos != NULL);
692
693         g_array_set_size(g_pids, 0);
694
695         if (!get_pids(g_pids))
696                 return false;
697
698         update_proc_infos(g_pids, proc_infos, terminated_proc_infos);
699         pick_valid_proc_infos(proc_infos, valid_proc_infos, total_valid_proc_time);
700
701         return true;
702
703 }
704
705 API void proc_stat_finalize(void)
706 {
707         if (g_pids) {
708                 g_array_free(g_pids, true);
709                 g_pids = NULL;
710         }
711
712         if (proc_infos) {
713                 g_array_free(proc_infos, true);
714                 proc_infos = NULL;
715         }
716 }
717
718
719 API unsigned int proc_stat_get_gpu_clock(void)
720 {
721         FILE *fp;
722         unsigned int clock;
723
724         fp = fopen("/sys/module/mali/parameters/mali_gpu_clk", "r");
725         if (fp == NULL)
726                 return -1;
727
728         if (fscanf(fp, "%d", &clock) < 1) {
729                 fclose(fp);
730                 return -1;
731         }
732
733         fclose(fp);
734
735         return clock;
736 }
737
738 bool proc_stat_is_gpu_on(void)
739 {
740         if (proc_stat_get_gpu_clock() <= 0)
741                 return false;
742
743         return true;
744 }
745
746
747
748 static inline int send_int(int fd, int val)
749 {
750         return write(fd, &val, sizeof(int));
751 }
752
753 static inline int send_str(int fd, char *str)
754 {
755         int len;
756         int ret;
757         if (str == NULL) {
758                 len = 0;
759                 ret = write(fd, &len, sizeof(int));
760         } else {
761                 len = strlen(str);
762                 if (len > NOTI_MAXARGLEN)
763                         len = NOTI_MAXARGLEN;
764                 ret = write(fd, &len, sizeof(int));
765                 if (ret < 0) {
766                         _E("%s: write failed\n", __FUNCTION__);
767                         return ret;
768                 }
769                 ret = write(fd, str, len);
770         }
771         return ret;
772 }
773
774 static int send_socket(struct resourced_noti *msg, bool sync)
775 {
776         int client_len;
777         int client_sockfd;
778         int result = 0;
779         struct sockaddr_un clientaddr;
780         int i;
781         int ret;
782
783         client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
784         if (client_sockfd == -1) {
785                 _E("%s: socket create failed\n", __FUNCTION__);
786                 return -1;
787         }
788
789         bzero(&clientaddr, sizeof(clientaddr));
790         clientaddr.sun_family = AF_UNIX;
791         strncpy(clientaddr.sun_path, RESOURCED_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
792         client_len = sizeof(clientaddr);
793
794         if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) <
795             0) {
796                 _E("%s: connect failed\n", __FUNCTION__);
797                 close(client_sockfd);
798                 return RESOURCED_ERROR_FAIL;
799         }
800
801         send_int(client_sockfd, msg->pid);
802         send_int(client_sockfd, msg->type);
803         send_str(client_sockfd, msg->path);
804         send_int(client_sockfd, msg->argc);
805         for (i = 0; i < msg->argc; i++)
806                 send_str(client_sockfd, msg->argv[i]);
807
808         if (sync) {
809                 ret = read(client_sockfd, &result, sizeof(int));
810                 if (ret < 0) {
811                         _E("%s: read failed\n", __FUNCTION__);
812                         close(client_sockfd);
813                         return RESOURCED_ERROR_FAIL;
814                 }
815         }
816
817         close(client_sockfd);
818         return result;
819 }
820
821 static resourced_ret_c proc_cgroup_send_status(const int type, int num, ...)
822 {
823         struct resourced_noti *msg;
824         resourced_ret_c ret = RESOURCED_ERROR_NONE;
825         va_list argptr;
826
827         int i;
828         char *args = NULL;
829         bool sync = SYNC_OPERATION(type);
830
831         msg = malloc(sizeof(struct resourced_noti));
832
833         if (msg == NULL)
834                 return RESOURCED_ERROR_OUT_OF_MEMORY;
835
836         msg->pid = getpid();
837         msg->type = type;
838         msg->path = NULL;
839
840         msg->argc = num;
841         va_start(argptr, num);
842         /* it's just for debug purpose to test error reporting */
843         for (i = 0; i < num; i++) {
844                 args = va_arg(argptr, char *);
845                 msg->argv[i] = args;
846         }
847         va_end(argptr);
848
849         ret = send_socket(msg, sync);
850         if (ret < 0)
851                 ret = RESOURCED_ERROR_FAIL;
852
853         free(msg);
854
855         return ret;
856 }
857
858 API resourced_ret_c proc_cgroup_foregrd(void)
859 {
860         char buf[MAX_DEC_SIZE(int)];
861         snprintf(buf, sizeof(buf), "%d", getpid());
862         return proc_cgroup_send_status(PROC_CGROUP_SET_FOREGRD, 1, buf);
863 }
864
865 API resourced_ret_c proc_cgroup_backgrd(void)
866 {
867         char buf[MAX_DEC_SIZE(int)];
868         snprintf(buf, sizeof(buf), "%d", getpid());
869         return proc_cgroup_send_status(PROC_CGROUP_SET_BACKGRD, 1, buf);
870 }
871
872 API resourced_ret_c proc_cgroup_active(pid_t pid)
873 {
874         char buf[MAX_DEC_SIZE(int)];
875         snprintf(buf, sizeof(buf), "%d", pid);
876         return proc_cgroup_send_status(PROC_CGROUP_SET_ACTIVE, 1, buf);
877 }
878
879 API resourced_ret_c proc_cgroup_inactive(pid_t pid)
880 {
881         char buf[MAX_DEC_SIZE(int)];
882         snprintf(buf, sizeof(buf), "%d", pid);
883         return proc_cgroup_send_status(PROC_CGROUP_SET_INACTIVE, 1, buf);
884 }
885
886 API resourced_ret_c proc_group_change_status(int type, pid_t pid, char* app_id)
887 {
888         char pid_buf[MAX_DEC_SIZE(int)];
889         char appid_buf[NOTI_MAXARGLEN];
890         snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
891         snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
892         return proc_cgroup_send_status(type, 2, pid_buf, appid_buf);
893 }
894
895 API resourced_ret_c proc_cgroup_sweep_memory(void)
896 {
897         char buf[MAX_DEC_SIZE(int)];
898         snprintf(buf, sizeof(buf), "%d", getpid());
899         return proc_cgroup_send_status(PROC_CGROUP_GET_MEMSWEEP, 1, buf);
900 }
901
902 API resourced_ret_c proc_cgroup_launch(int type, pid_t pid, char* app_id, char* pkg_id)
903 {
904         char pid_buf[MAX_DEC_SIZE(int)];
905         char appid_buf[NOTI_MAXARGLEN];
906         char pkgid_buf[NOTI_MAXARGLEN];
907         snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
908         snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
909         snprintf(pkgid_buf, sizeof(pkgid_buf)-1, "%s", pkg_id);
910         return proc_cgroup_send_status(type, 3, pid_buf, appid_buf, pkgid_buf);
911 }
912