1 /* IOHandler.c - IOMultiplexer v2
2 * Copyright (C) 2014 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
22 #include "IOGarbageCollector.h"
24 #include "IODNSLookup.h"
27 #include "compat/usleep.c"
30 static pthread_mutex_t iothread_sync;
32 #define pthread_self_tid() pthread_self().p
34 #define pthread_self_tid() pthread_self()
39 static struct IOHandlerThread {
41 unsigned int main : 1;
43 unsigned int shutdown : 1;
45 static pthread_t *thread;
47 struct IOHandlerThread *next;
50 static int iohandler_running = 0;
51 static int iohandler_treads = 1;
52 static struct IOHandlerThread *threads;
54 void iohandler_init() {
55 IOTHREAD_MUTEX_INIT(iothread_sync);
63 iohandler_running = 1;
66 void iohandler_set_threads(int threadcount) {
67 iohandler_treads = threadcount;
70 void iohandler_stop() {
75 static void iohandler_start_worker() {
76 struct IOHandlerThread *thread = calloc(1, sizeof(*thread));
78 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOHandlerThread in %s:%d", __FILE__, __LINE__);
81 struct IOHandlerThread *cthread;
82 for(cthread = threads; cthread; cthread = cthread->next) {
83 if(cthread->next == NULL) {
84 cthread->next = thread;
92 thread_err = pthread_create(&thread->thread, NULL, iohandler_worker, thread);
95 iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
100 static void iohandler_worker(void *tptr) {
101 struct IOHandlerThread *thread = tptr;
103 #ifdef HAVE_PTHREAD_H
105 thread->id = pthread_self_tid();
109 while(!thread->shutdown) { // endless loop
110 if(thread->main && iohandler_treads != iohandler_running) {
111 IOSYNCHRONIZE(iothread_sync);
112 #ifdef HAVE_PTHREAD_H
114 if(iohandler_treads > iohandler_running) {
115 for(i = 0; i < (iohandler_treads - iohandler_running); i++)
116 iohandler_start_worker();
118 if(iohandler_treads < iohandler_running) {
119 struct IOHandlerThread *cthread;
120 for(i = 0; i < (iohandler_running - iohandler_treads); i++) {
121 for(cthread = threads; cthread; cthread = cthread->next) {
124 cthread->shutdown = 1;
125 iolog_trigger(IOLOG_ERROR, "Thread %d marked for shutdown.", cthread->id);
132 if(iohandler_treads == 0) {
133 #ifdef HAVE_PTHREAD_H
134 struct IOHandlerThread *cthread;
135 for(cthread = threads; cthread; cthread = cthread->next) {
138 cthread->shutdown = 1;
139 pthread_join(cthread->thread, NULL);
142 thread->shutdown = 1;
143 IODESYNCHRONIZE(iothread_sync);
146 IODESYNCHRONIZE(iothread_sync);
149 usleep(500000); // 500ms
158 IOSYNCHRONIZE(iothread_sync);
159 if(thread == threads) {
160 threads = thread->next;
162 struct IOHandlerThread *cthread;
163 for(cthread = threads; cthread; cthread = cthread->next) {
164 if(cthread->next == thread) {
165 cthread->next = thread->next;
170 iolog_trigger(IOLOG_DEBUG, "Thread %d stopped.", thread->id);
172 IODESYNCHRONIZE(iothread_sync);
175 void iohandler_run() {
176 if(!iohandler_running)
178 iohandler_running = 1;
180 struct IOHandlerThread *mainthread = calloc(1, sizeof(*mainthread));
182 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOHandlerThread in %s:%d", __FILE__, __LINE__);
185 threads = mainthread;
187 mainthread->main = 1;
189 mainthread->shutdown = 0;
193 _stop_iodns(); /* possible worker thread */