2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program 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 General Public License
18 #include <utils/debug.h>
19 #include <threading/spinlock.h>
20 #include <threading/thread.h>
21 #include <collections/hashtable.h>
22 #include <collections/array.h>
25 typedef struct private_thread_t private_thread_t
;
27 struct private_thread_t
{
35 * GetCurrentThreadId() of thread
40 * Printable thread id returned by thread_current_id()
45 * Windows thread handle
50 * Main function of this thread (NULL for the main thread).
55 * Argument for the main function.
65 * Stack of cleanup handlers, as cleanup_t
70 * Thread specific values for this thread
85 * Is thread in cancellable state
90 * Has the thread been cancelled by thread->cancel()?
95 * Did we schedule an APC to docancel()?
100 * Active condition variable thread is waiting in, if any
102 CONDITION_VARIABLE
*condvar
;
106 * Global list of threads, GetCurrentThreadId() => private_thread_t
108 static hashtable_t
*threads
;
111 * Lock for threads table
113 static spinlock_t
*threads_lock
;
116 * Counter to assign printable thread IDs
118 static u_int threads_ids
= 0;
121 * Forward declaration
123 static private_thread_t
*create_internal(DWORD id
);
126 * Set leak detective state
128 static inline bool set_leak_detective(bool state
)
130 #ifdef LEAK_DETECTIVE
131 if (lib
&& lib
->leak_detective
)
133 return lib
->leak_detective
->set_state(lib
->leak_detective
, state
);
140 * Store thread in index
142 static void put_thread(private_thread_t
*this)
146 old
= set_leak_detective(FALSE
);
147 threads_lock
->lock(threads_lock
);
149 this = threads
->put(threads
, (void*)(uintptr_t)this->id
, this);
151 threads_lock
->unlock(threads_lock
);
152 set_leak_detective(old
);
156 * Remove thread from index
158 static void remove_thread(private_thread_t
*this)
162 old
= set_leak_detective(FALSE
);
163 threads_lock
->lock(threads_lock
);
165 threads
->remove(threads
, (void*)(uintptr_t)this->id
);
167 threads_lock
->unlock(threads_lock
);
168 set_leak_detective(old
);
172 * Get thread data for calling thread
174 static private_thread_t
*get_current_thread()
176 private_thread_t
*this;
178 threads_lock
->lock(threads_lock
);
180 this = threads
->get(threads
, (void*)(uintptr_t)GetCurrentThreadId());
182 threads_lock
->unlock(threads_lock
);
186 this = create_internal(GetCurrentThreadId());
196 void* thread_tls_put(void *key
, void *value
)
198 private_thread_t
*thread
;
201 thread
= get_current_thread();
203 old
= set_leak_detective(FALSE
);
204 value
= thread
->tls
->put(thread
->tls
, key
, value
);
205 set_leak_detective(old
);
213 void* thread_tls_get(void *key
)
215 private_thread_t
*thread
;
219 thread
= get_current_thread();
221 old
= set_leak_detective(FALSE
);
222 value
= thread
->tls
->get(thread
->tls
, key
);
223 set_leak_detective(old
);
231 void* thread_tls_remove(void *key
)
233 private_thread_t
*thread
;
237 thread
= get_current_thread();
239 old
= set_leak_detective(FALSE
);
240 threads_lock
->lock(threads_lock
);
241 value
= thread
->tls
->remove(thread
->tls
, key
);
242 threads_lock
->unlock(threads_lock
);
243 set_leak_detective(old
);
251 void thread_tls_remove_all(void *key
)
253 private_thread_t
*thread
;
254 enumerator_t
*enumerator
;
258 old
= set_leak_detective(FALSE
);
259 threads_lock
->lock(threads_lock
);
261 enumerator
= threads
->create_enumerator(threads
);
262 while (enumerator
->enumerate(enumerator
, NULL
, &thread
))
264 value
= thread
->tls
->remove(thread
->tls
, key
);
267 set_leak_detective(old
);
268 thread_tls_cleanup(value
);
269 set_leak_detective(FALSE
);
272 enumerator
->destroy(enumerator
);
274 threads_lock
->unlock(threads_lock
);
275 set_leak_detective(old
);
279 * Thread cleanup data
282 /** Cleanup callback function */
284 /** Argument provided to the cleanup function */
289 * Invoke pushed/tls cleanup handlers
291 static void docleanup(private_thread_t
*this)
293 enumerator_t
*enumerator
;
294 cleanup_t cleanup
, *tls
;
297 old
= set_leak_detective(FALSE
);
299 while (array_remove(this->cleanup
, -1, &cleanup
))
301 set_leak_detective(old
);
302 cleanup
.cb(cleanup
.arg
);
303 set_leak_detective(FALSE
);
306 threads_lock
->lock(threads_lock
);
307 enumerator
= this->tls
->create_enumerator(this->tls
);
308 while (enumerator
->enumerate(enumerator
, NULL
, &tls
))
310 this->tls
->remove_at(this->tls
, enumerator
);
312 set_leak_detective(old
);
313 thread_tls_cleanup(tls
);
314 set_leak_detective(FALSE
);
316 enumerator
->destroy(enumerator
);
317 threads_lock
->unlock(threads_lock
);
319 set_leak_detective(old
);
323 * Clean up and destroy a thread
325 static void destroy(private_thread_t
*this)
331 old
= set_leak_detective(FALSE
);
333 array_destroy(this->cleanup
);
334 this->tls
->destroy(this->tls
);
337 CloseHandle(this->handle
);
341 set_leak_detective(old
);
345 * End a thread, destroy when detached
347 static void end_thread(private_thread_t
*this)
356 this->terminated
= TRUE
;
364 void thread_set_active_condvar(CONDITION_VARIABLE
*condvar
)
366 private_thread_t
*thread
;
368 thread
= get_current_thread();
370 threads_lock
->lock(threads_lock
);
371 thread
->condvar
= condvar
;
372 threads_lock
->unlock(threads_lock
);
374 /* this is a cancellation point, as condvar wait is one */
379 * APC to cancel a thread
381 static void docancel(private_thread_t
*this)
383 /* make sure cancel() does not access this anymore */
384 threads_lock
->lock(threads_lock
);
385 threads_lock
->unlock(threads_lock
);
391 METHOD(thread_t
, cancel
, void,
392 private_thread_t
*this)
394 this->canceled
= TRUE
;
395 if (this->cancelability
)
397 threads_lock
->lock(threads_lock
);
398 if (!this->cancel_pending
)
400 this->cancel_pending
= TRUE
;
401 QueueUserAPC((void*)docancel
, this->handle
, (uintptr_t)this);
404 WakeAllConditionVariable(this->condvar
);
407 threads_lock
->unlock(threads_lock
);
411 METHOD(thread_t
, kill_
, void,
412 private_thread_t
*this, int sig
)
416 METHOD(thread_t
, detach
, void,
417 private_thread_t
*this)
419 this->detached
= TRUE
;
422 METHOD(thread_t
, join
, void*,
423 private_thread_t
*this)
432 while (!this->terminated
)
434 /* join is a cancellation point, use alertable wait */
435 WaitForSingleObjectEx(this->handle
, INFINITE
, TRUE
);
447 * Main function wrapper for threads
449 static DWORD
thread_cb(private_thread_t
*this)
451 /* Enable cancelability once the thread starts. We must check for any
452 * pending cancellation request an queue the APC that gets executed
453 * at the first cancellation point. */
454 this->cancelability
= TRUE
;
460 this->ret
= this->main(this->arg
);
468 * Create an internal thread object.
470 static private_thread_t
*create_internal(DWORD id
)
472 private_thread_t
*this;
475 old
= set_leak_detective(FALSE
);
484 .cleanup
= array_create(sizeof(cleanup_t
), 0),
485 .tls
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 4),
487 .cancelability
= TRUE
,
490 set_leak_detective(old
);
492 threads_lock
->lock(threads_lock
);
493 this->tid
= threads_ids
++;
494 threads_lock
->unlock(threads_lock
);
498 this->handle
= OpenThread(THREAD_ALL_ACCESS
, FALSE
, id
);
504 * Described in header.
506 thread_t
*thread_create(thread_main_t main
, void *arg
)
508 private_thread_t
*this;
510 this = create_internal(0);
514 /* not cancellable until started */
515 this->cancelability
= FALSE
;
517 this->handle
= CreateThread(NULL
, 0, (void*)thread_cb
, this,
518 CREATE_SUSPENDED
, &this->id
);
527 DBG2(DBG_LIB
, "created thread %u", this->id
);
529 ResumeThread(this->handle
);
531 return &this->public;
535 * Described in header.
537 thread_t
*thread_current()
539 return &get_current_thread()->public;
543 * Described in header.
545 u_int
thread_current_id()
547 return get_current_thread()->tid
;
551 * Described in header.
553 void thread_cleanup_push(thread_cleanup_t cb
, void *arg
)
555 private_thread_t
*this;
556 cleanup_t cleanup
= {
562 this = get_current_thread();
564 old
= set_leak_detective(FALSE
);
565 array_insert(this->cleanup
, -1, &cleanup
);
566 set_leak_detective(old
);
570 * Described in header
572 void thread_cleanup_pop(bool execute
)
574 private_thread_t
*this;
575 cleanup_t cleanup
= {};
578 this = get_current_thread();
580 old
= set_leak_detective(FALSE
);
581 array_remove(this->cleanup
, -1, &cleanup
);
582 set_leak_detective(old
);
586 cleanup
.cb(cleanup
.arg
);
591 * Described in header.
593 bool thread_cancelability(bool enable
)
595 private_thread_t
*this;
598 this = get_current_thread();
599 old
= this->cancelability
;
600 this->cancelability
= enable
;
602 if (enable
&& !old
&& this->canceled
)
610 * Described in header.
612 void thread_cancellation_point()
616 old
= thread_cancelability(TRUE
);
618 thread_cancelability(old
);
622 * Described in header.
624 void thread_exit(void *val
)
626 private_thread_t
*this;
628 this = get_current_thread();
636 * Described in header.
640 threads_lock
= spinlock_create();
641 threads
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 4);
643 /* reset counter should we initialize more than once */
646 put_thread(create_internal(GetCurrentThreadId()));
650 * Described in header.
652 void threads_deinit()
654 private_thread_t
*this;
656 this = threads
->remove(threads
, (void*)(uintptr_t)GetCurrentThreadId());
659 threads_lock
->destroy(threads_lock
);
660 threads
->destroy(threads
);