Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
hook.c
Go to the documentation of this file.
1 /*
2  * hook.c
3  * Copyright 2011 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <glib.h>
21 #include <pthread.h>
22 
23 #include "core.h"
24 #include "hook.h"
25 
26 typedef struct {
28  void * user;
31 } HookItem;
32 
33 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
34 static GHashTable * hooks; /* of (GQueue of (HookItem *) *) */
35 
36 EXPORT void hook_associate (const char * name, HookFunction func, void * user)
37 {
38  pthread_mutex_lock (& mutex);
39 
40  if (! hooks)
41  hooks = g_hash_table_new_full (g_str_hash, g_str_equal,
42  (GDestroyNotify) str_unref, (GDestroyNotify) g_queue_free);
43 
44  GQueue * list = g_hash_table_lookup (hooks, name);
45 
46  if (! list)
47  g_hash_table_insert (hooks, str_get (name), list = g_queue_new ());
48 
49  HookItem * item = g_slice_new (HookItem);
50  item->func = func;
51  item->user = user;
52  item->lock_count = 0;
53  item->remove_flag = FALSE;
54 
55  g_queue_push_tail (list, item);
56 
57  pthread_mutex_unlock (& mutex);
58 }
59 
60 EXPORT void hook_dissociate_full (const char * name, HookFunction func, void * user)
61 {
62  pthread_mutex_lock (& mutex);
63 
64  if (! hooks)
65  goto DONE;
66 
67  GQueue * list = g_hash_table_lookup (hooks, name);
68 
69  if (! list)
70  goto DONE;
71 
72  for (GList * node = list->head; node;)
73  {
74  HookItem * item = node->data;
75  GList * next = node->next;
76 
77  if (item->func == func && (! user || item->user == user))
78  {
79  if (item->lock_count)
80  item->remove_flag = TRUE;
81  else
82  {
83  g_queue_delete_link (list, node);
84  g_slice_free (HookItem, item);
85  }
86  }
87 
88  node = next;
89  }
90 
91  if (! list->head)
92  g_hash_table_remove (hooks, name);
93 
94 DONE:
95  pthread_mutex_unlock (& mutex);
96 }
97 
98 EXPORT void hook_call (const char * name, void * data)
99 {
100  pthread_mutex_lock (& mutex);
101 
102  if (! hooks)
103  goto DONE;
104 
105  GQueue * list = g_hash_table_lookup (hooks, name);
106 
107  if (! list)
108  goto DONE;
109 
110  for (GList * node = list->head; node;)
111  {
112  HookItem * item = node->data;
113 
114  if (! item->remove_flag)
115  {
116  item->lock_count ++;
117  pthread_mutex_unlock (& mutex);
118 
119  item->func (data, item->user);
120 
121  pthread_mutex_lock (& mutex);
122  item->lock_count --;
123  }
124 
125  GList * next = node->next;
126 
127  if (item->remove_flag && ! item->lock_count)
128  {
129  g_queue_delete_link (list, node);
130  g_slice_free (HookItem, item);
131  }
132 
133  node = next;
134  }
135 
136  if (! list->head)
137  g_hash_table_remove (hooks, name);
138 
139 DONE:
140  pthread_mutex_unlock (& mutex);
141 }