Release version 0.15.20
[platform/core/appfw/launchpad.git] / src / launchpad / src / launchpad_worker.c
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define _GNU_SOURCE
18 #include <errno.h>
19 #include <glib.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/syscall.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #include "launchpad_worker.h"
30 #include "log_private.h"
31
32 struct job_s {
33         worker_job_cb callback;
34         void *user_data;
35 };
36
37 struct worker_s {
38         GThread *thread;
39         GMutex mutex;
40         GCond cond;
41         GQueue *queue;
42 };
43
44 static struct worker_s __worker;
45
46 int _worker_add_job(worker_job_cb callback, void *user_data)
47 {
48         struct job_s *job;
49
50         if (!callback) {
51                 _E("Invalid parameter");
52                 return -EINVAL;
53         }
54
55         job = malloc(sizeof(struct job_s));
56         if (!job) {
57                 _E("Out of memory");
58                 return -ENOMEM;
59         }
60
61         job->callback = callback;
62         job->user_data = user_data;
63
64         g_mutex_lock(&__worker.mutex);
65         g_queue_push_tail(__worker.queue, job);
66         g_cond_signal(&__worker.cond);
67         g_mutex_unlock(&__worker.mutex);
68
69         return 0;
70 }
71
72 static int __set_comm(const char *name)
73 {
74         int fd;
75         ssize_t bytes_written;
76         char path[PATH_MAX];
77         pid_t tid = syscall(__NR_gettid);
78
79         _I("[%s] TID(%d)", name, tid);
80         snprintf(path, sizeof(path), "/proc/%d/comm", tid);
81         fd = open(path, O_WRONLY);
82         if (fd < 0) {
83                 _E("Failed to open %s. error(%d)", path, errno);
84                 return -1;
85         }
86
87         bytes_written = write(fd, name, strlen(name) + 1);
88         if (bytes_written < 0) {
89                 _E("Failed to write name(%s)", name);
90                 close(fd);
91                 return -1;
92         }
93
94         close(fd);
95         return 0;
96 }
97
98 static gpointer __worker_thread_cb(gpointer data)
99 {
100         struct worker_s *worker = (struct worker_s *)data;
101         struct job_s *job;
102         bool done = false;
103
104         __set_comm("worker");
105         do {
106                 g_mutex_lock(&worker->mutex);
107                 if (g_queue_is_empty(worker->queue))
108                         g_cond_wait(&worker->cond, &worker->mutex);
109
110                 job = (struct job_s *)g_queue_pop_head(worker->queue);
111                 g_mutex_unlock(&worker->mutex);
112                 done = job->callback(job->user_data);
113                 free(job);
114         } while (!done);
115
116         return NULL;
117 }
118
119 int _worker_init(void)
120 {
121         _W("WORKER_INIT");
122
123         g_mutex_init(&__worker.mutex);
124         g_cond_init(&__worker.cond);
125
126         __worker.queue = g_queue_new();
127         if (!__worker.queue) {
128                 _E("g_queue_new() is failed");
129                 return -ENOMEM;
130         }
131
132         __worker.thread = g_thread_new("worker", __worker_thread_cb, &__worker);
133         if (!__worker.thread) {
134                 _E("g_thread_new() is failed");
135                 return -ENOMEM;
136         }
137
138         return 0;
139 }
140
141 static bool __worker_done_cb(void *user_data)
142 {
143         _W("Done");
144         return true;
145 }
146
147 void _worker_fini(void)
148 {
149         _W("WORKER_FINI");
150
151         if (__worker.thread) {
152                 _worker_add_job(__worker_done_cb, NULL);
153                 g_thread_join(__worker.thread);
154         }
155
156         if (__worker.queue)
157                 g_queue_free_full(__worker.queue, (GDestroyNotify)free);
158
159         g_cond_clear(&__worker.cond);
160         g_mutex_clear(&__worker.mutex);
161 }