[kdbus] Do not set body message if signature field is empty
[platform/upstream/glib.git] / gio / gthreadedsocketservice.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2009 Codethink Limited
4  * Copyright © 2009 Red Hat, Inc
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2 of the licence or (at
9  * your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General
17  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Ryan Lortie <desrt@desrt.ca>
20  *          Alexander Larsson <alexl@redhat.com>
21  */
22
23 /**
24  * SECTION:gthreadedsocketservice
25  * @title: GThreadedSocketService
26  * @short_description: A threaded GSocketService
27  * @include: gio/gio.h
28  * @see_also: #GSocketService.
29  *
30  * A #GThreadedSocketService is a simple subclass of #GSocketService
31  * that handles incoming connections by creating a worker thread and
32  * dispatching the connection to it by emitting the
33  * #GThreadedSocketService::run signal in the new thread.
34  *
35  * The signal handler may perform blocking IO and need not return
36  * until the connection is closed.
37  *
38  * The service is implemented using a thread pool, so there is a
39  * limited amount of threads available to serve incoming requests.
40  * The service automatically stops the #GSocketService from accepting
41  * new connections when all threads are busy.
42  *
43  * As with #GSocketService, you may connect to #GThreadedSocketService::run,
44  * or subclass and override the default handler.
45  */
46
47 #include "config.h"
48 #include "gsocketconnection.h"
49 #include "gthreadedsocketservice.h"
50 #include "glibintl.h"
51
52 struct _GThreadedSocketServicePrivate
53 {
54   GThreadPool *thread_pool;
55   int max_threads;
56   gint job_count;
57 };
58
59 static guint g_threaded_socket_service_run_signal;
60
61 G_DEFINE_TYPE_WITH_PRIVATE (GThreadedSocketService,
62                             g_threaded_socket_service,
63                             G_TYPE_SOCKET_SERVICE)
64
65 enum
66 {
67   PROP_0,
68   PROP_MAX_THREADS
69 };
70
71 G_LOCK_DEFINE_STATIC(job_count);
72
73 typedef struct
74 {
75   GSocketConnection *connection;
76   GObject *source_object;
77 } GThreadedSocketServiceData;
78
79 static void
80 g_threaded_socket_service_func (gpointer _data,
81                                 gpointer user_data)
82 {
83   GThreadedSocketService *threaded = user_data;
84   GThreadedSocketServiceData *data = _data;
85   gboolean result;
86
87   g_signal_emit (threaded, g_threaded_socket_service_run_signal,
88                  0, data->connection, data->source_object, &result);
89
90   g_object_unref (data->connection);
91   if (data->source_object)
92     g_object_unref (data->source_object);
93   g_slice_free (GThreadedSocketServiceData, data);
94
95   G_LOCK (job_count);
96   if (threaded->priv->job_count-- == threaded->priv->max_threads)
97     g_socket_service_start (G_SOCKET_SERVICE (threaded));
98   G_UNLOCK (job_count);
99
100   g_object_unref (threaded);
101 }
102
103 static gboolean
104 g_threaded_socket_service_incoming (GSocketService    *service,
105                                     GSocketConnection *connection,
106                                     GObject           *source_object)
107 {
108   GThreadedSocketService *threaded;
109   GThreadedSocketServiceData *data;
110
111   threaded = G_THREADED_SOCKET_SERVICE (service);
112
113   data = g_slice_new (GThreadedSocketServiceData);
114
115   /* Ref the socket service for the thread */
116   g_object_ref (service);
117
118   data->connection = g_object_ref (connection);
119   if (source_object)
120     data->source_object = g_object_ref (source_object);
121   else
122     data->source_object = NULL;
123
124   G_LOCK (job_count);
125   if (++threaded->priv->job_count == threaded->priv->max_threads)
126     g_socket_service_stop (service);
127   G_UNLOCK (job_count);
128
129   g_thread_pool_push (threaded->priv->thread_pool, data, NULL);
130
131
132
133   return FALSE;
134 }
135
136 static void
137 g_threaded_socket_service_init (GThreadedSocketService *service)
138 {
139   service->priv = g_threaded_socket_service_get_instance_private (service);
140   service->priv->max_threads = 10;
141 }
142
143 static void
144 g_threaded_socket_service_constructed (GObject *object)
145 {
146   GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
147
148   service->priv->thread_pool =
149     g_thread_pool_new  (g_threaded_socket_service_func,
150                         service,
151                         service->priv->max_threads,
152                         FALSE,
153                         NULL);
154 }
155
156
157 static void
158 g_threaded_socket_service_finalize (GObject *object)
159 {
160   GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
161
162   g_thread_pool_free (service->priv->thread_pool, FALSE, FALSE);
163
164   G_OBJECT_CLASS (g_threaded_socket_service_parent_class)
165     ->finalize (object);
166 }
167
168 static void
169 g_threaded_socket_service_get_property (GObject    *object,
170                                         guint       prop_id,
171                                         GValue     *value,
172                                         GParamSpec *pspec)
173 {
174   GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
175
176   switch (prop_id)
177     {
178       case PROP_MAX_THREADS:
179         g_value_set_int (value, service->priv->max_threads);
180         break;
181
182       default:
183         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
184     }
185 }
186
187 static void
188 g_threaded_socket_service_set_property (GObject      *object,
189                                         guint         prop_id,
190                                         const GValue *value,
191                                         GParamSpec   *pspec)
192 {
193   GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
194
195   switch (prop_id)
196     {
197       case PROP_MAX_THREADS:
198         service->priv->max_threads = g_value_get_int (value);
199         break;
200
201       default:
202         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203     }
204 }
205
206
207 static void
208 g_threaded_socket_service_class_init (GThreadedSocketServiceClass *class)
209 {
210   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
211   GSocketServiceClass *ss_class = &class->parent_class;
212
213   gobject_class->constructed = g_threaded_socket_service_constructed;
214   gobject_class->finalize = g_threaded_socket_service_finalize;
215   gobject_class->set_property = g_threaded_socket_service_set_property;
216   gobject_class->get_property = g_threaded_socket_service_get_property;
217
218   ss_class->incoming = g_threaded_socket_service_incoming;
219
220   /**
221    * GThreadedSocketService::run:
222    * @service: the #GThreadedSocketService.
223    * @connection: a new #GSocketConnection object.
224    * @source_object: the source_object passed to g_socket_listener_add_address().
225    *
226    * The ::run signal is emitted in a worker thread in response to an
227    * incoming connection. This thread is dedicated to handling
228    * @connection and may perform blocking IO. The signal handler need
229    * not return until the connection is closed.
230    *
231    * Returns: %TRUE to stop further signal handlers from being called
232    */
233   g_threaded_socket_service_run_signal =
234     g_signal_new ("run", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST,
235                   G_STRUCT_OFFSET (GThreadedSocketServiceClass, run),
236                   g_signal_accumulator_true_handled, NULL,
237                   NULL, G_TYPE_BOOLEAN,
238                   2, G_TYPE_SOCKET_CONNECTION, G_TYPE_OBJECT);
239
240   g_object_class_install_property (gobject_class, PROP_MAX_THREADS,
241                                    g_param_spec_int ("max-threads",
242                                                      P_("Max threads"),
243                                                      P_("The max number of threads handling clients for this service"),
244                                                      -1,
245                                                      G_MAXINT,
246                                                      10,
247                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
248 }
249
250 /**
251  * g_threaded_socket_service_new:
252  * @max_threads: the maximal number of threads to execute concurrently
253  *   handling incoming clients, -1 means no limit
254  *
255  * Creates a new #GThreadedSocketService with no listeners. Listeners
256  * must be added with one of the #GSocketListener "add" methods.
257  *
258  * Returns: a new #GSocketService.
259  *
260  * Since: 2.22
261  */
262 GSocketService *
263 g_threaded_socket_service_new (int max_threads)
264 {
265   return g_object_new (G_TYPE_THREADED_SOCKET_SERVICE,
266                        "max-threads", max_threads,
267                        NULL);
268 }