1 /*
2 This file is part of Deadbeef Player source code
3 http://deadbeef.sourceforge.net
4
5 message pump implementation
6
7 Copyright (C) 2009-2013 Alexey Yakovenko
8
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any damages
11 arising from the use of this software.
12
13 Permission is granted to anyone to use this software for any purpose,
14 including commercial applications, and to alter it and redistribute it
15 freely, subject to the following restrictions:
16
17 1. The origin of this software must not be misrepresented; you must not
18 claim that you wrote the original software. If you use this software
19 in a product, an acknowledgment in the product documentation would be
20 appreciated but is not required.
21 2. Altered source versions must be plainly marked as such, and must not be
22 misrepresented as being the original software.
23 3. This notice may not be removed or altered from any source distribution.
24
25 Alexey Yakovenko waker@users.sourceforge.net
26 */
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <stdlib.h>
31 #include "messagepump.h"
32 #include "threading.h"
33 #include "playlist.h"
34
35 typedef struct message_s {
36 uint32_t id;
37 uintptr_t ctx;
38 uint32_t p1;
39 uint32_t p2;
40 struct message_s *next;
41 } message_t;
42
43 enum { MAX_MESSAGES = 100 };
44 static message_t pool[MAX_MESSAGES];
45 static message_t *mfree;
46 static message_t *mqueue;
47 static message_t *mqtail;
48 static uintptr_t mutex;
49 static uintptr_t cond;
50
51 static void
52 messagepump_reset (void);
53
54 int
messagepump_init(void)55 messagepump_init (void) {
56 messagepump_reset ();
57 mutex = mutex_create ();
58 cond = cond_create ();
59 return 0;
60 }
61
62 void
messagepump_free()63 messagepump_free () {
64 mutex_lock (mutex);
65 messagepump_reset ();
66 mutex_unlock (mutex);
67 mutex_free (mutex);
68 cond_free (cond);
69 }
70
71 static void
messagepump_reset(void)72 messagepump_reset (void) {
73 mqueue = NULL;
74 mfree = NULL;
75 mqtail = NULL;
76 memset (pool, 0, sizeof (pool));
77 for (int i = 0; i < MAX_MESSAGES; i++) {
78 pool[i].next = mfree;
79 mfree = &pool[i];
80 }
81 }
82
83 int
messagepump_push(uint32_t id,uintptr_t ctx,uint32_t p1,uint32_t p2)84 messagepump_push (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
85 if (!mfree) {
86 //fprintf (stderr, "WARNING: message queue is full! message ignored (%d %p %d %d)\n", id, (void*)ctx, p1, p2);
87 if (id >= DB_EV_FIRST && ctx) {
88 messagepump_event_free ((ddb_event_t *)ctx);
89 }
90 return -1;
91 }
92 mutex_lock (mutex);
93 message_t *msg = mfree;
94 mfree = mfree->next;
95 if (mqtail) {
96 mqtail->next = msg;
97 }
98 mqtail = msg;
99 if (!mqueue) {
100 mqueue = msg;
101 }
102
103 msg->next = NULL;
104 msg->id = id;
105 msg->ctx = ctx;
106 msg->p1 = p1;
107 msg->p2 = p2;
108 mutex_unlock (mutex);
109 cond_signal (cond);
110 return 0;
111 }
112
113 void
messagepump_wait(void)114 messagepump_wait (void) {
115 cond_wait (cond, mutex);
116 mutex_unlock (mutex);
117 }
118
119 int
messagepump_pop(uint32_t * id,uintptr_t * ctx,uint32_t * p1,uint32_t * p2)120 messagepump_pop (uint32_t *id, uintptr_t *ctx, uint32_t *p1, uint32_t *p2) {
121 mutex_lock (mutex);
122 if (!mqueue) {
123 mutex_unlock (mutex);
124 return -1;
125 }
126 *id = mqueue->id;
127 *ctx = mqueue->ctx;
128 *p1 = mqueue->p1;
129 *p2 = mqueue->p2;
130 message_t *next = mqueue->next;
131 mqueue->next = mfree;
132 mfree = mqueue;
133 mqueue = next;
134 if (!mqueue) {
135 mqtail = NULL;
136 }
137 mutex_unlock (mutex);
138 return 0;
139 }
140
141 int
messagepump_hasmessages(void)142 messagepump_hasmessages (void) {
143 return mqueue ? 1 : 0;
144 }
145
146 ddb_event_t *
messagepump_event_alloc(uint32_t id)147 messagepump_event_alloc (uint32_t id) {
148 int sz = 0;
149 ddb_event_t *ev;
150 switch (id) {
151 case DB_EV_SONGCHANGED:
152 sz = sizeof (ddb_event_trackchange_t);
153 break;
154 case DB_EV_SONGSTARTED:
155 case DB_EV_SONGFINISHED:
156 case DB_EV_TRACKINFOCHANGED:
157 sz = sizeof (ddb_event_track_t);
158 break;
159 case DB_EV_SEEKED:
160 sz = sizeof (ddb_event_playpos_t);
161 break;
162 }
163 assert (("Invalid event %d to use with messagepump_event_alloc, use sendmessage instead\n", id));
164 ev = malloc (sz);
165 memset (ev, 0, sz);
166 ev->event = id;
167 ev->size = sz;
168 return ev;
169 }
170
171 void
messagepump_event_free(ddb_event_t * ev)172 messagepump_event_free (ddb_event_t *ev) {
173 switch (ev->event) {
174 case DB_EV_SONGCHANGED:
175 {
176 ddb_event_trackchange_t *tc = (ddb_event_trackchange_t*)ev;
177 if (tc->from) {
178 pl_item_unref ((playItem_t *)tc->from);
179 }
180 if (tc->to) {
181 pl_item_unref ((playItem_t *)tc->to);
182 }
183 }
184 break;
185 case DB_EV_SONGSTARTED:
186 case DB_EV_SONGFINISHED:
187 case DB_EV_TRACKINFOCHANGED:
188 {
189 ddb_event_track_t *tc = (ddb_event_track_t*)ev;
190 if (tc->track) {
191 pl_item_unref ((playItem_t *)tc->track);
192 }
193 }
194 break;
195 case DB_EV_SEEKED:
196 {
197 ddb_event_playpos_t *tc = (ddb_event_playpos_t*)ev;
198 if (tc->track) {
199 pl_item_unref ((playItem_t *)tc->track);
200 }
201 }
202 break;
203 }
204 free (ev);
205 }
206
207 int
messagepump_push_event(ddb_event_t * ev,uint32_t p1,uint32_t p2)208 messagepump_push_event (ddb_event_t *ev, uint32_t p1, uint32_t p2) {
209 return messagepump_push (ev->event, (uintptr_t)ev, p1, p2);
210 }
211
212