1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "threadpool.h"
30 #include "context.h"
31
32 #ifndef _WIN32
33
34 #include <pthread.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38
39 static threadpool_job kill_job;
40
41 UiThreadpool* threadpool_new(
int min,
int max) {
42 UiThreadpool *pool = malloc(
sizeof(UiThreadpool));
43 pool->queue =
NULL;
44 pool->queue_len =
0;
45 pool->num_idle =
0;
46 pool->min_threads = min;
47 pool->max_threads = max;
48
49 pthread_mutex_init(&pool->queue_lock,
NULL);
50 pthread_mutex_init(&pool->avlbl_lock,
NULL);
51 pthread_cond_init(&pool->available,
NULL);
52
53 return pool;
54 }
55
56 int threadpool_start(UiThreadpool *pool) {
57
58 for(
int i=
0;i<pool->min_threads;i++) {
59 pthread_t t;
60 if (pthread_create(&t,
NULL, threadpool_func, pool) !=
0) {
61 fprintf(stderr,
"uic: threadpool_start: pthread_create failed: %s", strerror(errno));
62 return 1;
63 }
64 }
65 return 0;
66 }
67
68 void* threadpool_func(
void *data) {
69 UiThreadpool *pool = (UiThreadpool*)data;
70
71 for(;;) {
72 threadpool_job *job = threadpool_get_job(pool);
73 if(job == &kill_job) {
74 break;
75 }
76
77 job->callback(job->data);
78
79 free(job);
80 }
81 return NULL;
82 }
83
84 threadpool_job* threadpool_get_job(UiThreadpool *pool) {
85 pthread_mutex_lock(&pool->queue_lock);
86
87 threadpool_job *job =
NULL;
88 pool->num_idle++;
89 while(job ==
NULL) {
90 if(pool->queue_len ==
0) {
91 pthread_cond_wait(&pool->available, &pool->queue_lock);
92 continue;
93 }
else {
94 pool_queue_t *q = pool->queue;
95 job = q->job;
96 pool->queue = q->next;
97 pool->queue_len--;
98 free(q);
99 }
100 }
101 pool->num_idle--;
102
103 pthread_mutex_unlock(&pool->queue_lock);
104 return job;
105 }
106
107 void threadpool_run(UiThreadpool *pool, job_callback_f func,
void *data) {
108
109
110 threadpool_job *job = malloc(
sizeof(threadpool_job));
111 job->callback = func;
112 job->data = data;
113
114 pthread_mutex_lock(&pool->queue_lock);
115 threadpool_enqueue_job(pool, job);
116
117 int create_thread =
0;
118 int destroy_thread =
0;
119 int diff = pool->queue_len - pool->num_idle;
120
121
122 pthread_cond_signal(&pool->available);
123
124
125 pthread_mutex_unlock(&pool->queue_lock);
126 }
127
128 void threadpool_enqueue_job(UiThreadpool *pool, threadpool_job *job) {
129 pool_queue_t *q = malloc(
sizeof(
pool_queue_t));
130 q->job = job;
131 q->next =
NULL;
132
133 if(pool->queue ==
NULL) {
134 pool->queue = q;
135 }
else {
136 pool_queue_t *last_elem = pool->queue;
137 while(last_elem->next !=
NULL) {
138 last_elem = last_elem->next;
139 }
140 last_elem->next = q;
141 }
142 pool->queue_len++;
143 }
144
145
146
147
148
149
150 UiThreadpool* ui_threadpool_create(
int nthreads) {
151 UiThreadpool *pool = threadpool_new(nthreads, nthreads);
152 threadpool_start(pool);
153 return pool;
154 }
155
156 void ui_threadpool_destroy(UiThreadpool* pool) {
157
158 }
159
160 static int ui_threadpool_job_finish(
void *data) {
161 UiJob *job = data;
162 UiEvent event;
163 event.obj = job->obj;
164 event.window = job->obj->window;
165 event.document = job->obj->ctx->document;
166 event.intval =
0;
167 event.eventdata =
NULL;
168 job->finish_callback(&event, job->finish_data);
169 free(job);
170 return 0;
171 }
172
173 static void* ui_threadpool_job_func(
void *data) {
174 UiJob *job = data;
175 if (!job->job_func(job->job_data) && job->finish_callback) {
176 ui_call_mainthread(ui_threadpool_job_finish, job);
177 }
else {
178 free(job);
179 }
180 return NULL;
181 }
182
183 void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf,
void* td, ui_callback f,
void* fd) {
184 UiJob* job = malloc(
sizeof(UiJob));
185 job->obj = obj;
186 job->job_func = tf;
187 job->job_data = td;
188 job->finish_callback = f;
189 job->finish_data = fd;
190 threadpool_run(pool, ui_threadpool_job_func, job);
191 }
192
193
194 #endif
195
196