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 "config.h"
24 #include "core.h"
25 #include "hook.h"
26 
27 typedef struct {
29  void * user;
32 } HookItem;
33 
34 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
35 static GHashTable * hooks; /* of (GQueue of (HookItem *) *) */
36 
37 /* str_unref() may be a macro */
38 static void str_unref_cb (void * str)
39 {
40  str_unref (str);
41 }
42 
43 EXPORT void hook_associate (const char * name, HookFunction func, void * user)
44 {
45  pthread_mutex_lock (& mutex);
46 
47  if (! hooks)
48  hooks = g_hash_table_new_full (g_str_hash, g_str_equal, str_unref_cb,
49  (GDestroyNotify) g_queue_free);
50 
51  GQueue * list = g_hash_table_lookup (hooks, name);
52 
53  if (! list)
54  g_hash_table_insert (hooks, str_get (name), list = g_queue_new ());
55 
56  HookItem * item = g_slice_new (HookItem);
57  item->func = func;
58  item->user = user;
59  item->lock_count = 0;
60  item->remove_flag = FALSE;
61 
62  g_queue_push_tail (list, item);
63 
64  pthread_mutex_unlock (& mutex);
65 }
66 
67 EXPORT void hook_dissociate_full (const char * name, HookFunction func, void * user)
68 {
69  pthread_mutex_lock (& mutex);
70 
71  if (! hooks)
72  goto DONE;
73 
74  GQueue * list = g_hash_table_lookup (hooks, name);
75 
76  if (! list)
77  goto DONE;
78 
79  for (GList * node = list->head; node;)
80  {
81  HookItem * item = node->data;
82  GList * next = node->next;
83 
84  if (item->func == func && (! user || item->user == user))
85  {
86  if (item->lock_count)
87  item->remove_flag = TRUE;
88  else
89  {
90  g_queue_delete_link (list, node);
91  g_slice_free (HookItem, item);
92  }
93  }
94 
95  node = next;
96  }
97 
98  if (! list->head)
99  g_hash_table_remove (hooks, name);
100 
101 DONE:
102  pthread_mutex_unlock (& mutex);
103 }
104 
105 EXPORT void hook_call (const char * name, void * data)
106 {
107  pthread_mutex_lock (& mutex);
108 
109  if (! hooks)
110  goto DONE;
111 
112  GQueue * list = g_hash_table_lookup (hooks, name);
113 
114  if (! list)
115  goto DONE;
116 
117  for (GList * node = list->head; node;)
118  {
119  HookItem * item = node->data;
120 
121  if (! item->remove_flag)
122  {
123  item->lock_count ++;
124  pthread_mutex_unlock (& mutex);
125 
126  item->func (data, item->user);
127 
128  pthread_mutex_lock (& mutex);
129  item->lock_count --;
130  }
131 
132  GList * next = node->next;
133 
134  if (item->remove_flag && ! item->lock_count)
135  {
136  g_queue_delete_link (list, node);
137  g_slice_free (HookItem, item);
138  }
139 
140  node = next;
141  }
142 
143  if (! list->head)
144  g_hash_table_remove (hooks, name);
145 
146 DONE:
147  pthread_mutex_unlock (& mutex);
148 }