1 /***
2 This file is part of avahi.
3
4 avahi is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 avahi is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <sys/poll.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <pthread.h>
32 #include <signal.h>
33
34 #include "llist.h"
35 #include "avahi-malloc.h"
36 #include "timeval.h"
37 #include "simple-watch.h"
38 #include "thread-watch.h"
39
40 struct AvahiThreadedPoll {
41 AvahiSimplePoll *simple_poll;
42 pthread_t thread_id;
43 pthread_mutex_t mutex;
44 int thread_running;
45 int retval;
46 };
47
poll_func(struct pollfd * ufds,unsigned int nfds,int timeout,void * userdata)48 static int poll_func(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata) {
49 pthread_mutex_t *mutex = userdata;
50 int r;
51
52 /* Before entering poll() we unlock the mutex, so that
53 * avahi_simple_poll_quit() can succeed from another thread. */
54
55 pthread_mutex_unlock(mutex);
56 r = poll(ufds, nfds, timeout);
57 pthread_mutex_lock(mutex);
58
59 return r;
60 }
61
thread(void * userdata)62 static void* thread(void *userdata){
63 AvahiThreadedPoll *p = userdata;
64 sigset_t mask;
65
66 /* Make sure that signals are delivered to the main thread */
67 sigfillset(&mask);
68 pthread_sigmask(SIG_BLOCK, &mask, NULL);
69
70 pthread_mutex_lock(&p->mutex);
71 p->retval = avahi_simple_poll_loop(p->simple_poll);
72 pthread_mutex_unlock(&p->mutex);
73
74 return NULL;
75 }
76
avahi_threaded_poll_new(void)77 AvahiThreadedPoll *avahi_threaded_poll_new(void) {
78 AvahiThreadedPoll *p;
79
80 if (!(p = avahi_new(AvahiThreadedPoll, 1)))
81 goto fail; /* OOM */
82
83 if (!(p->simple_poll = avahi_simple_poll_new()))
84 goto fail;
85
86 pthread_mutex_init(&p->mutex, NULL);
87
88 avahi_simple_poll_set_func(p->simple_poll, poll_func, &p->mutex);
89
90 p->thread_running = 0;
91
92 return p;
93
94 fail:
95 if (p) {
96 if (p->simple_poll) {
97 avahi_simple_poll_free(p->simple_poll);
98 pthread_mutex_destroy(&p->mutex);
99 }
100
101 avahi_free(p);
102 }
103
104 return NULL;
105 }
106
avahi_threaded_poll_free(AvahiThreadedPoll * p)107 void avahi_threaded_poll_free(AvahiThreadedPoll *p) {
108 assert(p);
109
110 /* Make sure that this function is not called from the helper thread */
111 assert(!p->thread_running || !pthread_equal(pthread_self(), p->thread_id));
112
113 if (p->thread_running)
114 avahi_threaded_poll_stop(p);
115
116 if (p->simple_poll)
117 avahi_simple_poll_free(p->simple_poll);
118
119 pthread_mutex_destroy(&p->mutex);
120 avahi_free(p);
121 }
122
avahi_threaded_poll_get(AvahiThreadedPoll * p)123 const AvahiPoll* avahi_threaded_poll_get(AvahiThreadedPoll *p) {
124 assert(p);
125
126 return avahi_simple_poll_get(p->simple_poll);
127 }
128
avahi_threaded_poll_start(AvahiThreadedPoll * p)129 int avahi_threaded_poll_start(AvahiThreadedPoll *p) {
130 assert(p);
131
132 assert(!p->thread_running);
133
134 if (pthread_create(&p->thread_id, NULL, thread, p) < 0)
135 return -1;
136
137 p->thread_running = 1;
138
139 return 0;
140 }
141
avahi_threaded_poll_stop(AvahiThreadedPoll * p)142 int avahi_threaded_poll_stop(AvahiThreadedPoll *p) {
143 assert(p);
144
145 if (!p->thread_running)
146 return -1;
147
148 /* Make sure that this function is not called from the helper thread */
149 assert(!pthread_equal(pthread_self(), p->thread_id));
150
151 pthread_mutex_lock(&p->mutex);
152 avahi_simple_poll_quit(p->simple_poll);
153 pthread_mutex_unlock(&p->mutex);
154
155 pthread_join(p->thread_id, NULL);
156 p->thread_running = 0;
157
158 return p->retval;
159 }
160
avahi_threaded_poll_quit(AvahiThreadedPoll * p)161 void avahi_threaded_poll_quit(AvahiThreadedPoll *p) {
162 assert(p);
163
164 /* Make sure that this function is called from the helper thread */
165 assert(pthread_equal(pthread_self(), p->thread_id));
166
167 avahi_simple_poll_quit(p->simple_poll);
168 }
169
avahi_threaded_poll_lock(AvahiThreadedPoll * p)170 void avahi_threaded_poll_lock(AvahiThreadedPoll *p) {
171 assert(p);
172
173 /* Make sure that this function is not called from the helper thread */
174 assert(!p->thread_running || !pthread_equal(pthread_self(), p->thread_id));
175
176 pthread_mutex_lock(&p->mutex);
177 }
178
avahi_threaded_poll_unlock(AvahiThreadedPoll * p)179 void avahi_threaded_poll_unlock(AvahiThreadedPoll *p) {
180 assert(p);
181
182 /* Make sure that this function is not called from the helper thread */
183 assert(!p->thread_running || !pthread_equal(pthread_self(), p->thread_id));
184
185 pthread_mutex_unlock(&p->mutex);
186 }
187