1 /*
2 * Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23
24 #include "librws.h"
25 #include "rws_thread.h"
26 #include "rws_memory.h"
27 #include "rws_common.h"
28
29 #include <assert.h>
30 #include <pthread.h>
31 #include <semaphore.h>
32 #include <unistd.h>
33 #include <sys/time.h>
34
35 struct rws_thread_struct {
36 rws_thread_funct thread_function;
37 void * user_object;
38 pthread_t thread;
39 };
40
41 typedef struct _rws_threads_joiner_struct {
42 rws_thread thread;
43 rws_mutex mutex;
44 } _rws_threads_joiner;
45
46 static _rws_threads_joiner * _threads_joiner = NULL;
rws_threads_joiner_clean(void)47 static void rws_threads_joiner_clean(void) { // private
48 rws_thread t = _threads_joiner->thread;
49 void * r = NULL;
50
51 if (!t) {
52 return;
53 }
54 _threads_joiner->thread = NULL;
55 pthread_join(t->thread, &r);
56 assert(r == NULL);
57
58 rws_free(t);
59 }
60
rws_threads_joiner_add(rws_thread thread)61 static void rws_threads_joiner_add(rws_thread thread) { // public
62 rws_mutex_lock(_threads_joiner->mutex);
63 rws_threads_joiner_clean();
64 _threads_joiner->thread = thread;
65 rws_mutex_unlock(_threads_joiner->mutex);
66 }
67
rws_threads_joiner_create_ifneed(void)68 static void rws_threads_joiner_create_ifneed(void) {
69 if (_threads_joiner) {
70 return;
71 }
72 _threads_joiner = (_rws_threads_joiner *)rws_malloc_zero(sizeof(_rws_threads_joiner));
73 _threads_joiner->mutex = rws_mutex_create_recursive();
74 }
75
rws_thread_func_priv(void * some_pointer)76 static void * rws_thread_func_priv(void * some_pointer) {
77 rws_thread t = (rws_thread)some_pointer;
78 t->thread_function(t->user_object);
79 rws_threads_joiner_add(t);
80
81 return NULL;
82 }
83
rws_thread_create(rws_thread_funct thread_function,void * user_object)84 rws_thread rws_thread_create(rws_thread_funct thread_function, void * user_object) {
85 rws_thread t = NULL;
86 int res = -1;
87 pthread_attr_t attr;
88
89 if (!thread_function) {
90 return NULL;
91 }
92 rws_threads_joiner_create_ifneed();
93 t = (rws_thread)rws_malloc_zero(sizeof(struct rws_thread_struct));
94 t->user_object = user_object;
95 t->thread_function = thread_function;
96 if (pthread_attr_init(&attr) == 0) {
97 pthread_attr_setstacksize(&attr, 16 * 1024);
98 struct sched_param sched;
99 #ifndef _AMLOGIC_
100 sched.sched_priority = 32;
101 #else
102 sched.sched_priority = 3;
103 #endif
104 pthread_attr_setschedparam(&attr, &sched);
105 //if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0) {
106 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0) {
107 res = pthread_create(&t->thread, &attr, &rws_thread_func_priv, (void *)t);
108 pthread_setname_np(t->thread, "GnWebsoc");
109 }
110 //}
111 pthread_attr_destroy(&attr);
112 }
113 assert(res == 0);
114 return t;
115 }
116
rws_thread_sleep(const unsigned int millisec)117 void rws_thread_sleep(const unsigned int millisec) {
118 usleep(millisec * 1000); // 1s = 1'000'000 microsec.
119 }
120
rws_mutex_create_recursive(void)121 rws_mutex rws_mutex_create_recursive(void) {
122 pthread_mutex_t * mutex = (pthread_mutex_t *)rws_malloc_zero(sizeof(pthread_mutex_t));
123 int res = -1;
124 pthread_mutexattr_t attr;
125 if (pthread_mutexattr_init(&attr) == 0) {
126 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0) {
127 res = pthread_mutex_init(mutex, &attr);
128 }
129 pthread_mutexattr_destroy(&attr);
130 }
131 assert(res == 0);
132 return mutex;
133 }
134
rws_mutex_lock(rws_mutex mutex)135 void rws_mutex_lock(rws_mutex mutex) {
136 if (mutex) {
137 pthread_mutex_lock((pthread_mutex_t *)mutex);
138 }
139 }
140
rws_mutex_unlock(rws_mutex mutex)141 void rws_mutex_unlock(rws_mutex mutex) {
142 if (mutex) {
143 pthread_mutex_unlock((pthread_mutex_t *)mutex);
144 }
145 }
146
rws_mutex_delete(rws_mutex mutex)147 void rws_mutex_delete(rws_mutex mutex) {
148 if (mutex) {
149 pthread_mutex_destroy((pthread_mutex_t *)mutex);
150 rws_free(mutex);
151 }
152 }
153
rws_sem_create(void)154 rws_sem rws_sem_create(void)
155 {
156 int ret = -1;
157 sem_t *sem = (sem_t *) rws_malloc_zero(sizeof(sem_t));
158
159 if (sem)
160 ret = sem_init(sem, 0, 0);
161
162 assert(ret == 0);
163
164 return sem;
165 }
166
rws_sem_delete(rws_sem sem)167 void rws_sem_delete(rws_sem sem)
168 {
169 if (sem) {
170 sem_destroy(sem);
171 rws_free(sem);
172 }
173 }
174
rws_sem_signal(rws_sem sem)175 void rws_sem_signal(rws_sem sem)
176 {
177 if (sem) {
178 sem_post(sem);
179 }
180 }
181
rws_sem_wait(rws_sem sem,unsigned int timeout_ms)182 int rws_sem_wait(rws_sem sem, unsigned int timeout_ms)
183 {
184 int ret = -1;
185
186 if (sem) {
187 if (timeout_ms == RWS_WAIT_FOREVER) {
188 ret = sem_wait(sem);
189 } else {
190 struct timespec abs_timeout;
191 struct timeval tv;
192 gettimeofday(&tv, NULL);
193
194 abs_timeout.tv_sec = tv.tv_sec + timeout_ms / 1000;
195 abs_timeout.tv_nsec = tv.tv_usec * 1000 + (timeout_ms % 1000) * 1000000;
196 ret = sem_timedwait(sem, &abs_timeout);
197 }
198 }
199
200 return ret;
201 }
202