1 /*
2 * e-operation-pool.c
3 *
4 * Copyright (C) 2011 Novell, Inc. (www.novell.com)
5 *
6 * This library is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "e-operation-pool.h"
21
22 struct _EOperationPool {
23 GThreadPool *pool;
24
25 GMutex ops_lock;
26 GHashTable *ops;
27 guint32 last_opid;
28 };
29
30 /**
31 * e_operation_pool_new: (skip)
32 * @max_threads: Maximum number of threads for this pool
33 * @thread_func: Function to run for a given thread
34 * @user_data: The user data to pass to @thread_func
35 *
36 * Returns: (transfer full): a new #EOperationPool with the given settings.
37 * Free it with e_operation_pool_free(), when no longer needed.
38 *
39 * Since: 3.2
40 **/
41 EOperationPool *
e_operation_pool_new(guint max_threads,GFunc thread_func,gpointer user_data)42 e_operation_pool_new (guint max_threads,
43 GFunc thread_func,
44 gpointer user_data)
45 {
46 EOperationPool *pool;
47 GThreadPool *thread_pool;
48 GError *error = NULL;
49
50 g_return_val_if_fail (thread_func != NULL, NULL);
51
52 thread_pool = g_thread_pool_new (thread_func, user_data, max_threads, FALSE, &error);
53 if (error) {
54 g_warning ("%s: Failed to create thread pool: %s", G_STRFUNC, error->message);
55 g_error_free (error);
56 return NULL;
57 }
58
59 pool = g_slice_new0 (EOperationPool);
60 pool->pool = thread_pool;
61 g_mutex_init (&pool->ops_lock);
62 pool->ops = g_hash_table_new (g_direct_hash, g_direct_equal);
63 pool->last_opid = 0;
64
65 /* Kill threads which don't do anything for 10 seconds */
66 g_thread_pool_set_max_idle_time (10 * 1000);
67
68 return pool;
69 }
70
71 /**
72 * e_operation_pool_free:
73 * @pool: an #EOperationPool
74 *
75 * Frees previously created @pool.
76 *
77 * Since: 3.2
78 **/
79 void
e_operation_pool_free(EOperationPool * pool)80 e_operation_pool_free (EOperationPool *pool)
81 {
82 g_return_if_fail (pool != NULL);
83
84 g_thread_pool_free (pool->pool, FALSE, FALSE);
85 g_mutex_clear (&pool->ops_lock);
86 g_hash_table_destroy (pool->ops);
87 g_slice_free (EOperationPool, pool);
88 }
89
90 /**
91 * e_operation_pool_reserve_opid:
92 * @pool: an #EOperationPool
93 *
94 * Reserves new operation ID, which is returned. This operation ID may
95 * be released by e_operation_pool_release_opid() when the operation
96 * is finished.
97 *
98 * Returns: a new operation ID
99 *
100 * Since: 3.2
101 **/
102 guint32
e_operation_pool_reserve_opid(EOperationPool * pool)103 e_operation_pool_reserve_opid (EOperationPool *pool)
104 {
105 guint32 opid;
106
107 g_return_val_if_fail (pool != NULL, 0);
108 g_return_val_if_fail (pool->ops != NULL, 0);
109
110 g_mutex_lock (&pool->ops_lock);
111
112 pool->last_opid++;
113 if (!pool->last_opid)
114 pool->last_opid = 1;
115
116 while (pool->last_opid && g_hash_table_lookup (pool->ops, GUINT_TO_POINTER (pool->last_opid)))
117 pool->last_opid++;
118
119 opid = pool->last_opid;
120 if (opid)
121 g_hash_table_insert (pool->ops, GUINT_TO_POINTER (opid), GUINT_TO_POINTER (1));
122
123 g_mutex_unlock (&pool->ops_lock);
124
125 g_return_val_if_fail (opid != 0, 0);
126
127 return opid;
128 }
129
130 /**
131 * e_operation_pool_release_opid:
132 * @pool: an #EOperationPool
133 * @opid: an operation ID
134 *
135 * Releases @opid previously reserved by e_operation_pool_reserve_opid().
136 *
137 * Since: 3.2
138 **/
139 void
e_operation_pool_release_opid(EOperationPool * pool,guint32 opid)140 e_operation_pool_release_opid (EOperationPool *pool,
141 guint32 opid)
142 {
143 g_return_if_fail (pool != NULL);
144 g_return_if_fail (pool->ops != NULL);
145
146 g_mutex_lock (&pool->ops_lock);
147 g_hash_table_remove (pool->ops, GUINT_TO_POINTER (opid));
148 g_mutex_unlock (&pool->ops_lock);
149 }
150
151 /**
152 * e_operation_pool_push:
153 * @pool: an #EOperationPool
154 * @opdata: user data for the operation
155 *
156 * Pushes an operation to be processed. @opdata is passed to the function
157 * provided in e_operation_pool_new().
158 *
159 * Since: 3.2
160 **/
161 void
e_operation_pool_push(EOperationPool * pool,gpointer opdata)162 e_operation_pool_push (EOperationPool *pool,
163 gpointer opdata)
164 {
165 GError *error = NULL;
166
167 g_return_if_fail (pool != NULL);
168 g_return_if_fail (pool->pool != NULL);
169
170 g_thread_pool_push (pool->pool, opdata, &error);
171
172 if (error) {
173 g_warning ("%s: Failed to push to thread pool: %s", G_STRFUNC, error->message);
174 g_error_free (error);
175 }
176 }
177