tizen 2.3.1 release
[kernel/api/system-resource.git] / src / logging / logging.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2012 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /*
20  * @file logging.c
21  *
22  * @desc start logging system for resourced
23  *
24  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
25  *
26  */
27
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <fcntl.h>
31 #include <assert.h>
32 #include <time.h>
33 #include <dirent.h>
34 #include <unistd.h>
35 #include <sys/sysinfo.h>
36 #include <sys/stat.h>
37 #include <glib.h>
38 #include <sys/time.h>
39 #include <sys/resource.h>
40 #include <Ecore.h>
41
42 #include "trace.h"
43 #include "logging-common.h"
44 #include "resourced.h"
45 #include "macro.h"
46 #include "module.h"
47 #include "proc-process.h"
48 #include "proc-main.h"
49 #include "proc_stat.h"
50 #include "logging.h"
51 #include "edbus-handler.h"
52
53 #define BUF_MAX                 1024
54 #define WRITE_INFO_MAX          10
55 #define MAX_PROC_LIST           200
56
57 #define WEBPROCESS_NAME         "WebProcess"
58 #define MAX_PROC_ITEM           200
59 #define INC_PROC_ITEM           10
60 #define COMMIT_INTERVAL         10*60   /* 10 min */
61 #define LOGGING_PTIORITY        -20
62
63 #define SIGNAL_LOGGING_INIT     "LoggingInit"
64 #define SIGNAL_LOGGING_GET      "LoggingGet"
65 #define SIGNAL_LOGGING_UPDATED  "LoggingUpdated"
66 #define PROC_OOM_SCORE_ADJ_PATH "/proc/%d/oom_score_adj"
67
68 struct logging_sub_sys {
69         const char *name;
70         time_t commit_interval;
71         time_t last_commit;
72         struct logging_info_ops *ops;
73 };
74
75 static const struct module_ops logging_modules_ops;
76 static const struct module_ops *logging_ops;
77
78 static int num_log_infos;
79 static bool need_to_update;
80 static GHashTable *logging_proc_list;
81 static GArray *logging_ss_list;
82 static pthread_t        logging_thread  = 0;
83 static pthread_mutex_t  logging_mutex   = PTHREAD_MUTEX_INITIALIZER;
84 static pthread_mutex_t  proc_list_mutex = PTHREAD_MUTEX_INITIALIZER;
85 static pthread_cond_t   logging_cond    = PTHREAD_COND_INITIALIZER;
86
87 static int init_logging_infos(struct logging_infos *info, const char *key,
88         pid_t pid, int oom, time_t now)
89 {
90         int i;
91         int ret;
92
93         if (!info) {
94                 _D("info is null");
95                 return RESOURCED_ERROR_FAIL;
96         }
97
98         info->oom = oom;
99         info->pid = pid;
100         info->running = true;
101
102         for (i = 0; i < logging_ss_list->len; i++) {
103                 struct logging_sub_sys *ss = &g_array_index(logging_ss_list,
104                                                 struct logging_sub_sys, i);
105                 ret = ss->ops->init(&(info->stats[i]), pid, oom, now);
106                 if (ret != RESOURCED_ERROR_NONE) {
107                         _E("init logging at %lu", now);
108                         /* not return error, just continue updating */
109                 }
110         }
111
112         return RESOURCED_ERROR_NONE;
113 }
114
115 static void update_logging_infos(struct logging_infos *info,
116         time_t now, unsigned first)
117 {
118         int i;
119         int ret;
120         for (i = 0; i < logging_ss_list->len; i++) {
121                 struct logging_sub_sys *ss = &g_array_index(logging_ss_list,
122                                                 struct logging_sub_sys, i);
123                 ret = ss->ops->update(info->stats[i], info->pid, info->oom, now, first);
124                 if (ret != RESOURCED_ERROR_NONE) {
125                         /*
126                          * when update failed, this is because there is no
127                          * running process. So, just update processes running
128                          * state.
129                          */
130                         info->running = false;
131                 }
132         }
133
134         return;
135 }
136
137 static void insert_hash_table(char *key, pid_t pid, int oom)
138 {
139         struct logging_infos *info;
140         void **stats;
141         char *name;
142         time_t now;
143
144         if (!key) {
145                 _D("input parameter key is NULL");
146                 return;
147         }
148
149         now = time(NULL);
150
151         name = strndup(key, strlen(key)+1);
152
153         if (!name) {
154                 _D("memory allocation for name failed");
155                 return;
156         }
157         info = (struct logging_infos *)malloc(sizeof(struct logging_infos));
158
159         if (!info) {
160                 _D("memory allocation for logging_infos failed");
161                 free(name);
162                 return;
163         }
164
165         stats = (void **)malloc(sizeof(void *) * num_log_infos);
166
167         if (!stats) {
168                 _D("memory allocation for log infos fails");
169                 free(name);
170                 free(info);
171                 return;
172         }
173
174         info->stats = stats;
175         init_logging_infos(info, name, pid, oom, now);
176
177         g_hash_table_insert(logging_proc_list, (gpointer) name, (gpointer) info);
178         update_logging_infos(info, now, true);
179         return;
180 }
181
182 static int write_journal(struct logging_sub_sys *pss, int ss_index)
183 {
184         gpointer value;
185         gpointer key;
186         int ret = RESOURCED_ERROR_NONE;
187         char *name;
188         GHashTableIter iter;
189         struct logging_infos *infos;
190         g_hash_table_iter_init(&iter, logging_proc_list);
191
192         while (1) {
193                 ret = pthread_mutex_lock(&proc_list_mutex);
194                 if (ret) {
195                         _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
196                         return ret;
197                 }
198
199                 if (!g_hash_table_iter_next(&iter, &key, &value)) {
200                         ret = pthread_mutex_unlock(&proc_list_mutex);
201                         if (ret) {
202                                 _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
203                                 return ret;
204                         }
205                         break;
206                 }
207
208                 name = (char *)key;
209                 infos = (struct logging_infos *)value;
210                 pss->ops->write(name, infos, ss_index);
211                 ret = pthread_mutex_unlock(&proc_list_mutex);
212                 if (ret) {
213                         _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
214                         return ret;
215                 }
216         }
217
218         return RESOURCED_ERROR_NONE;
219 }
220
221 static int write_logging_subsys_info(struct logging_sub_sys *pss, int sindex,
222         time_t now, bool force)
223 {
224
225         if (!force && now < pss->last_commit + pss->commit_interval)
226                 return RESOURCED_ERROR_NONE;
227
228         _D("start write %s subsys, now %lu, last:%lu, interval:%lu",
229                 pss->name, now, pss->last_commit, pss->commit_interval);
230
231         write_journal(pss, sindex);
232
233         pss->last_commit = now;
234         return RESOURCED_ERROR_NONE;
235
236 }
237
238 static int write_logging_infos(bool force)
239 {
240         int i;
241         int ret;
242         time_t now;
243
244         now = time(NULL);
245
246         for (i = 0; i < logging_ss_list->len; i++) {
247                 struct logging_sub_sys *ss = &g_array_index(logging_ss_list,
248                                                 struct logging_sub_sys, i);
249                 ret = write_logging_subsys_info(ss, i, now, force);
250                 if (ret != RESOURCED_ERROR_NONE) {
251                         _E("write logging at %lu", now);
252                         /* not return error, just continue updating */
253                 }
254         }
255
256         return RESOURCED_ERROR_NONE;
257 }
258
259 int register_logging_subsystem(const char*name, struct logging_info_ops *ops)
260 {
261         struct logging_sub_sys ss;
262         char *ss_name;
263         time_t now;
264
265         if (!name) {
266                 _E("input parameter name is NULL");
267                 return RESOURCED_ERROR_INVALID_PARAMETER;
268         }
269
270         ss_name = strndup(name, strlen(name)+1);
271
272         if (!ss_name) {
273                 _E("memory allocation for name is failed");
274                 return RESOURCED_ERROR_FAIL;
275         }
276
277         now = time(NULL);
278
279         ss.name = ss_name;
280         ss.commit_interval = COMMIT_INTERVAL;
281         ss.last_commit = now;
282         ss.ops = ops;
283
284         g_array_append_val(logging_ss_list, ss);
285         num_log_infos++;
286
287         return RESOURCED_ERROR_NONE;
288 }
289
290 int update_commit_interval(const char *name, time_t commit_interval)
291 {
292         int i;
293         for (i = 0; i < logging_ss_list->len; i++) {
294                 struct logging_sub_sys *ss = &g_array_index(logging_ss_list,
295                                                 struct logging_sub_sys, i);
296                 if (!strcmp(ss->name, name)) {
297                         ss->commit_interval = commit_interval;
298                         _D("%s logging subsystem commit interval updated to %lu",
299                         ss->name, ss->commit_interval);
300                         return RESOURCED_ERROR_NONE;
301                 }
302         }
303
304         _D("%s subsystem update fail, not exist", name);
305         return RESOURCED_ERROR_FAIL;
306 }
307
308 static inline int is_webprocess(char *name)
309 {
310         return !strcmp(name, WEBPROCESS_NAME);
311 }
312
313 static int rename_webprocess(pid_t pgid, char *name)
314 {
315         char webui_name[PROC_NAME_MAX];
316         int ret;
317
318         if ((ret = proc_get_cmdline(pgid, webui_name)) != RESOURCED_ERROR_NONE)
319                 return RESOURCED_ERROR_FAIL;
320
321         strcat(name, ".");
322         strcat(name, webui_name);
323
324         return RESOURCED_ERROR_NONE;
325 }
326
327 static int get_cmdline(pid_t pid, char *cmdline)
328 {
329         char buf[PROC_BUF_MAX];
330         FILE *fp;
331
332         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
333         fp = fopen(buf, "r");
334         if (fp == NULL)
335                 return RESOURCED_ERROR_FAIL;
336
337         if (fgets(cmdline, PROC_NAME_MAX-1, fp) == NULL) {
338                 fclose(fp);
339                 return RESOURCED_ERROR_FAIL;
340         }
341         fclose(fp);
342
343         return RESOURCED_ERROR_NONE;
344 }
345
346 static void insert_proc_list(pid_t pid, pid_t pgid, int oom)
347 {
348         int ret = RESOURCED_ERROR_NONE;
349         char name[PROC_NAME_MAX];
350         struct logging_infos *info;
351
352         ret = get_cmdline(pid, name);
353         /*
354          * if cmdline does not exist, remove item from queue
355          * and continue logging remaining items
356          */
357         if (ret != RESOURCED_ERROR_NONE) {
358                 return;
359         }
360
361         if (is_webprocess(name)) {
362                 ret = rename_webprocess(pgid, name);
363                 if (ret != RESOURCED_ERROR_NONE)
364                         return;
365
366         }
367
368         ret = pthread_mutex_lock(&proc_list_mutex);
369         if (ret) {
370                 _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
371                 return;
372         }
373
374         info = (struct logging_infos *)
375                 g_hash_table_lookup(logging_proc_list, name);
376
377         /* To Do: handle multiple daemons with the same name */
378         if (!info) {
379                 insert_hash_table(name, pid, oom);
380         } else {
381                 info->running = true;
382                 info->pid = pid;
383                 info->oom = oom;
384         }
385
386         ret = pthread_mutex_unlock(&proc_list_mutex);
387         if (ret) {
388                 _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
389                 return;
390         }
391         return;
392 }
393
394 static bool is_running_process(GArray *garray, pid_t pid)
395 {
396         int i;
397         pid_t tpid;
398
399         for (i = 0 ; i < garray->len; i++) {
400                 tpid = g_array_index(garray, pid_t, i);
401                 if (tpid == pid)
402                         return true;
403         }
404         return false;
405 }
406
407 static void update_proc_state(void)
408 {
409         DIR *dirp;
410         struct dirent entry;
411         struct dirent *result;
412         GArray *running_procs = NULL;
413         GHashTableIter iter;
414         int ret;
415         gpointer key, value;
416
417         running_procs = g_array_new(false, false, sizeof(pid_t));
418
419         if (!running_procs) {
420                 _E("fail to create garray for pids");
421                 return;
422         }
423
424         dirp = opendir("/proc");
425
426         if (dirp == NULL) {
427                 _E("/proc open is failed, and cannot updated running procs");
428                 return;
429         }
430
431         while (!(ret = readdir_r(dirp, &entry, &result)) && result != NULL) {
432                 pid_t pid;
433
434                 if (!isdigit(entry.d_name[0]))
435                         continue;
436                 pid = atoi(entry.d_name);
437                 g_array_append_val(running_procs, pid);
438         }
439
440         closedir(dirp);
441
442         if (ret) {
443                 _E("readdir_r on /proc directory failed");
444                 g_array_free(running_procs, true);
445                 return;
446         }
447
448         g_hash_table_iter_init(&iter, logging_proc_list);
449
450         ret = pthread_mutex_lock(&proc_list_mutex);
451         if (ret) {
452                 _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
453                 g_array_free(running_procs, true);
454                 return;
455         }
456
457         while (g_hash_table_iter_next(&iter, &key, &value)) {
458                 struct logging_infos *info = (struct logging_infos *)value;
459                 info->running = is_running_process(running_procs, info->pid);
460         }
461
462         g_array_free(running_procs, true);
463
464         ret = pthread_mutex_unlock(&proc_list_mutex);
465         if (ret) {
466                 _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
467                 return;
468         }
469
470         need_to_update = false;
471         return;
472 }
473
474 static void update_proc_list(void)
475 {
476         GHashTableIter iter;
477         gpointer key, value;
478         time_t now;
479         struct logging_infos *infos;
480         int ret;
481
482         if (need_to_update)
483                 update_proc_state();
484
485         now = time(NULL);
486
487         g_hash_table_iter_init(&iter, logging_proc_list);
488
489         while (1) {
490                 ret = pthread_mutex_lock(&proc_list_mutex);
491                 if (ret) {
492                         _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
493                         return;
494                 }
495
496                 if (!g_hash_table_iter_next(&iter, &key, &value)) {
497                         ret = pthread_mutex_unlock(&proc_list_mutex);
498                         if (ret) {
499                                 _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
500                                 return;
501                         }
502                         _D("finish proc list update");
503                         break;
504                 }
505                 infos = (struct logging_infos *)value;
506
507                 if (infos->running)
508                         update_logging_infos(infos, now, false);
509                 ret = pthread_mutex_unlock(&proc_list_mutex);
510                 if (ret) {
511                         _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
512                         return;
513                 }
514         }
515
516         return;
517 }
518
519 static void logging_update_state(void)
520 {
521         need_to_update = true;
522 }
523
524 static int check_running(gpointer key, gpointer value, gpointer user_data)
525 {
526         struct logging_infos *infos = (struct logging_infos *)value;
527
528         return !(infos->running);
529 }
530
531 static void reclaim_proc_list(void)
532 {
533         int ret;
534
535         ret = pthread_mutex_lock(&proc_list_mutex);
536         if (ret) {
537                 _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
538                 return;
539         }
540
541         g_hash_table_foreach_remove(logging_proc_list, check_running, NULL);
542         ret = pthread_mutex_unlock(&proc_list_mutex);
543         if (ret) {
544                 _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
545                 return;
546         }
547 }
548
549 static void logging(void)
550 {
551         update_proc_list();
552
553         if (g_hash_table_size(logging_proc_list) > MAX_PROC_LIST) {
554                 write_logging_infos(true);
555                 reclaim_proc_list();
556         } else
557                 write_logging_infos(false);
558 }
559
560 static void *logging_pthread(void *arg)
561 {
562         int ret = 0;
563
564         setpriority(PRIO_PROCESS, 0, LOGGING_PTIORITY);
565
566         while (1) {
567                 /*
568                  * When signalled by main thread,
569                  * it starts logging_pthread().
570                  */
571                 ret = pthread_mutex_lock(&logging_mutex);
572                 if ( ret ) {
573                         _E("logging thread::pthread_mutex_lock() failed, %d", ret);
574                         break;
575                 }
576
577                 ret = pthread_cond_wait(&logging_cond, &logging_mutex);
578                 if ( ret ) {
579                         _E("logging thread::pthread_cond_wait() failed, %d", ret);
580                         ret = pthread_mutex_unlock(&logging_mutex);
581                         if ( ret )
582                                 _E("logging thread::pthread_mutex_lock() failed, %d", ret);
583                         break;
584                 }
585
586                 logging();
587
588                 ret = pthread_mutex_unlock(&logging_mutex);
589                 if ( ret ) {
590                         _E("logging thread::pthread_mutex_unlock() failed, %d", ret);
591                         break;
592                 }
593         }
594
595         /* Now our thread finishes - cleanup TID */
596         logging_thread = 0;
597
598         return NULL;
599 }
600
601
602 static int logging_thread_create(void)
603 {
604         int ret = RESOURCED_ERROR_NONE;
605
606         if (logging_thread) {
607                 _I("logging thread %u already created", (unsigned)logging_thread);
608         } else {
609                 /* initialize logging_thread */
610                 ret = pthread_create(&logging_thread, NULL, (void *)logging_pthread, (void *)NULL);
611                 if (ret) {
612                         _E("pthread creation for logging_pthread failed, %d\n", ret);
613                         logging_thread = 0;
614                 } else {
615                         _D("pthread creation for logging success");
616                         pthread_detach(logging_thread);
617                 }
618         }
619
620         return ret;
621 }
622
623 static void free_key(gpointer key)
624 {
625         if (!key)
626                 free(key);
627 }
628
629 static void free_value(gpointer value)
630 {
631         int i;
632         struct logging_infos * info = (struct logging_infos *)value;
633
634         if (!info)
635                 return;
636
637         for (i = 0; i < num_log_infos; i++) {
638                 if (info->stats[i])
639                         free(info->stats[i]);
640         }
641
642         if (info->stats)
643                 free(info->stats);
644
645         free(info);
646 }
647
648 static void initialize_logging_proc_list(void)
649 {
650         DIR *dirp;
651         struct dirent entry;
652         struct dirent *result;
653         char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
654         int cur_oom = -1;
655         FILE *fp = NULL;
656         int ret;
657
658         dirp = opendir("/proc");
659
660         if (dirp == NULL) {
661                 _E("/proc open is failed, and cannot updated running procs");
662                 return;
663         }
664
665         while (!(ret = readdir_r(dirp, &entry, &result)) && result != NULL) {
666                 pid_t pid, pgid;
667
668                 if (!isdigit(entry.d_name[0]))
669                         continue;
670                 pid = atoi(entry.d_name);
671                 pgid = getpgid(pid);
672                 if (!pgid)
673                         continue;
674                 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
675                 fp = fopen(buf, "r+");
676                 if (fp == NULL)
677                         continue;
678                 if (fgets(buf, sizeof(buf), fp) == NULL) {
679                         fclose(fp);
680                         continue;
681                 }
682                 cur_oom = atoi(buf);
683                 fclose(fp);
684                 insert_proc_list(pid, pgid, cur_oom);
685         }
686
687         closedir(dirp);
688         write_logging_infos(true);
689         return;
690 }
691
692 static void logging_update_start(void)
693 {
694         int ret;
695         /* signal to logging_pthread to start */
696         ret = pthread_mutex_lock(&logging_mutex);
697         if (ret) {
698                 _E("logging_update_start::pthread_mutex_lock() failed, %d", ret);
699                 return;
700         }
701
702         ret = pthread_cond_signal(&logging_cond);
703         if (ret) {
704                 _E("logging_update_start::pthread_cond_wait() failed, %d", ret);
705                 ret = pthread_mutex_unlock(&logging_mutex);
706                 if ( ret )
707                         _E("logging_update_start::pthread_mutex_unlock() failed, %d", ret);
708                 return;
709         }
710
711         _D("send signal logging_pthread");
712         ret = pthread_mutex_unlock(&logging_mutex);
713         if (ret) {
714                 _E("logging_update_start::pthread_mutex_unlock() failed, %d", ret);
715                 return;
716         }
717 }
718
719 static void broadcast_logging_data_updated_signal(void)
720 {
721         int r;
722
723         r = broadcast_edbus_signal_str(RESOURCED_PATH_LOGGING, RESOURCED_INTERFACE_LOGGING,
724                         SIGNAL_LOGGING_UPDATED, NULL, NULL);
725         _I("broadcast logging_data updated signal!");
726
727         if (r < 0)
728                 _E("Failed: broadcast logging_data_updated signal");
729 }
730
731 static void logging_init_booting_done_edbus_signal_handler(void *data, DBusMessage *msg)
732 {
733         int ret;
734
735         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_LOGGING,
736                 SIGNAL_LOGGING_INIT);
737         if (ret == 0) {
738                 _D("there is booting done signal");
739                 return;
740         }
741         initialize_logging_proc_list();
742         _D("logging_init_booting_done_edbus_signal_handler");
743 }
744
745 static void logging_get_edbus_signal_handler(void *data, DBusMessage *msg)
746 {
747         int ret;
748
749         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_LOGGING,
750                 SIGNAL_LOGGING_GET);
751         if (ret == 0) {
752                 _D("there is logging get signal");
753                 return;
754         }
755         write_logging_infos(true);
756         _D("logging_get_edbus_signal_handler");
757         broadcast_logging_data_updated_signal();
758 }
759
760 static int logging_init(void)
761 {
762         int ret = RESOURCED_ERROR_NONE;
763
764         _D("logging_init start");
765
766         logging_proc_list = g_hash_table_new_full(
767                 g_str_hash,
768                 g_str_equal,
769                 free_key,
770                 free_value);
771
772         if (!logging_proc_list) {
773                 _E("fail g_hash_table_new_full() for logging_proc_list");
774                 return RESOURCED_ERROR_FAIL;
775         }
776
777         logging_ss_list = g_array_new(false, false,
778                 sizeof(struct logging_sub_sys));
779
780         if (logging_ss_list == NULL)
781                 return RESOURCED_ERROR_FAIL;
782
783         ret = logging_thread_create();
784         if (ret) {
785                 _E("logging thread create failed");
786                 return RESOURCED_ERROR_FAIL;
787         }
788
789         register_edbus_signal_handler(RESOURCED_PATH_LOGGING,
790                 RESOURCED_INTERFACE_LOGGING, SIGNAL_LOGGING_INIT,
791                     (void *)logging_init_booting_done_edbus_signal_handler);
792
793         register_edbus_signal_handler(RESOURCED_PATH_LOGGING,
794                 RESOURCED_INTERFACE_LOGGING, SIGNAL_LOGGING_GET,
795                     (void *)logging_get_edbus_signal_handler);
796
797         return RESOURCED_ERROR_NONE;
798 }
799
800 static int resourced_logging_control(void *data)
801 {
802         int ret = RESOURCED_ERROR_NONE;
803         struct logging_data_type *l_data;
804
805         if (!num_log_infos)
806                 return ret;
807
808         l_data = (struct logging_data_type *)data;
809
810         switch(l_data->control_type) {
811         case LOGGING_INSERT_PROC_LIST:
812                 if (l_data->args)
813                         insert_proc_list((pid_t)l_data->args[0],
814                                 (pid_t)l_data->args[1], (int)l_data->args[2]);
815                 break;
816         case LOGGING_UPDATE_PROC_INFO:
817                 logging_update_start();
818                 break;
819         case LOGGING_UPDATE_STATE:
820                 logging_update_state();
821                 break;
822         }
823         return ret;
824 }
825
826 static int resourced_logging_init(void *data)
827 {
828         logging_ops = &logging_modules_ops;
829
830         return logging_init();
831 }
832
833 static int resourced_logging_exit(void *data)
834 {
835         if (logging_ss_list)
836                 g_array_free(logging_ss_list, TRUE);
837         if (logging_proc_list)
838                 g_hash_table_destroy(logging_proc_list);
839         return RESOURCED_ERROR_NONE;
840 }
841
842 int logging_control(enum logging_control_type type, unsigned long *args)
843 {
844         struct logging_data_type l_data;
845
846         if (logging_ops) {
847                 l_data.control_type = type;
848                 l_data.args = args;
849                 return logging_ops->control(&l_data);
850         }
851
852         return RESOURCED_ERROR_NONE;
853 }
854
855 static const struct module_ops logging_modules_ops = {
856         .priority       = MODULE_PRIORITY_HIGH,
857         .name           = "logging",
858         .init           = resourced_logging_init,
859         .exit           = resourced_logging_exit,
860         .control        = resourced_logging_control,
861 };
862
863 MODULE_REGISTER(&logging_modules_ops)