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);
64 iohandler_running = 1;
67 void iohandler_set_threads(int threadcount) {
68 iohandler_treads = threadcount;
71 void iohandler_stop() {
76 static void iohandler_start_worker() {
77 struct IOHandlerThread *thread = calloc(1, sizeof(*thread));
79 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOHandlerThread in %s:%d", __FILE__, __LINE__);
82 struct IOHandlerThread *cthread;
83 for(cthread = threads; cthread; cthread = cthread->next) {
84 if(cthread->next == NULL) {
85 cthread->next = thread;
93 thread_err = pthread_create(&thread->thread, NULL, iohandler_worker, thread);
96 iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
101 static void iohandler_worker(void *tptr) {
102 struct IOHandlerThread *thread = tptr;
104 #ifdef HAVE_PTHREAD_H
106 thread->id = pthread_self_tid();
110 while(!thread->shutdown) { // endless loop
111 if(thread->main && iohandler_treads != iohandler_running) {
112 IOSYNCHRONIZE(iothread_sync);
113 #ifdef HAVE_PTHREAD_H
115 if(iohandler_treads > iohandler_running) {
116 for(i = 0; i < (iohandler_treads - iohandler_running); i++)
117 iohandler_start_worker();
119 if(iohandler_treads < iohandler_running) {
120 struct IOHandlerThread *cthread;
121 for(i = 0; i < (iohandler_running - iohandler_treads); i++) {
122 for(cthread = threads; cthread; cthread = cthread->next) {
125 cthread->shutdown = 1;
126 iolog_trigger(IOLOG_ERROR, "Thread %d marked for shutdown.", cthread->id);
133 if(iohandler_treads == 0) {
134 #ifdef HAVE_PTHREAD_H
135 struct IOHandlerThread *cthread;
136 for(cthread = threads; cthread; cthread = cthread->next) {
139 cthread->shutdown = 1;
140 pthread_join(cthread->thread, NULL);
143 thread->shutdown = 1;
144 IODESYNCHRONIZE(iothread_sync);
147 IODESYNCHRONIZE(iothread_sync);
150 usleep(500000); // 500ms
159 IOSYNCHRONIZE(iothread_sync);
160 if(thread == threads) {
161 threads = thread->next;
163 struct IOHandlerThread *cthread;
164 for(cthread = threads; cthread; cthread = cthread->next) {
165 if(cthread->next == thread) {
166 cthread->next = thread->next;
171 iolog_trigger(IOLOG_DEBUG, "Thread %d stopped.", thread->id);
173 IODESYNCHRONIZE(iothread_sync);
176 void iohandler_run() {
177 if(!iohandler_running)
179 iohandler_running = 1;
181 struct IOHandlerThread *mainthread = calloc(1, sizeof(*mainthread));
183 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOHandlerThread in %s:%d", __FILE__, __LINE__);
186 threads = mainthread;
188 mainthread->main = 1;
190 mainthread->shutdown = 0;
194 _stop_iodns(); /* possible worker thread */