1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "kc/system.h"
21
22 #include "kc/cb_list.h"
23
24 CallbackListEntry *CallbackListEntry::_free_list = 0;
25
CallbackListEntry(unsigned long long value,Callback * cb,void * data,CallbackListEntry * next)26 CallbackListEntry::CallbackListEntry(unsigned long long value,
27 Callback *cb,
28 void *data,
29 CallbackListEntry *next)
30 {
31 _cb = cb;
32 _data = data;
33 _next = next;
34 _value = value;
35 }
36
~CallbackListEntry(void)37 CallbackListEntry::~CallbackListEntry(void)
38 {
39 }
40
41 void
alloc_entries(void)42 CallbackListEntry::alloc_entries(void)
43 {
44 for (int a = 0;a < CALLBACK_LIST_ALLOC_SIZE;a++)
45 _free_list = ::new CallbackListEntry(0, 0, 0, _free_list);
46 }
47
48 void
free_entries(void)49 CallbackListEntry::free_entries(void)
50 {
51 for (CallbackListEntry *ptr = _free_list;ptr != NULL;)
52 {
53 CallbackListEntry *tmp = ptr;
54 ptr = ptr->_next;
55 delete tmp;
56 }
57 _free_list = 0;
58 }
59
60 void *
operator new(size_t size)61 CallbackListEntry::operator new(size_t size)
62 {
63 CallbackListEntry *ptr = _free_list;
64
65 if (ptr == NULL)
66 {
67 alloc_entries();
68 return ::new CallbackListEntry(0, 0, 0, 0);
69 }
70
71 _free_list = ptr->_next;
72 ptr->_next = 0; // don't leak internal list references
73 return ptr;
74 }
75
76 void
operator delete(void * p)77 CallbackListEntry::operator delete(void *p)
78 {
79 CallbackListEntry *ptr = (CallbackListEntry *)p;
80 ptr->_next = _free_list;
81 _free_list = ptr;
82 }
83
CallbackList()84 CallbackList::CallbackList()
85 {
86 _list = 0;
87 }
88
~CallbackList(void)89 CallbackList::~CallbackList(void)
90 {
91 clear();
92 CallbackListEntry::free_entries();
93 }
94
95 void
clear(void)96 CallbackList::clear(void)
97 {
98 CallbackListEntry *ptr;
99
100 while (_list)
101 {
102 ptr = _list;
103 _list = ptr->_next;
104 delete ptr;
105 }
106 }
107
108 void
add_callback(unsigned long long value,Callback * cb,void * data)109 CallbackList::add_callback(unsigned long long value,
110 Callback *cb,
111 void *data)
112 {
113 CallbackListEntry *ptr, *next;
114
115 if (_list == 0)
116 {
117 /*
118 * easy, empty list
119 */
120 _list = new CallbackListEntry(value, cb, data, 0);
121 }
122 else
123 {
124 ptr = _list;
125 if (_list->_value > value)
126 {
127 /*
128 * add front
129 */
130 _list = new CallbackListEntry(value, cb, data, ptr);
131 }
132 else
133 {
134 /*
135 * insert sorted
136 */
137 while (242)
138 {
139 if (ptr->_next && ptr->_next->_value > value)
140 {
141 next = ptr->_next;
142 ptr->_next = new CallbackListEntry(value, cb, data, next);
143 break;
144 }
145 else
146 {
147 if (ptr->_next == 0)
148 {
149 ptr->_next = new CallbackListEntry(value, cb, data, 0);
150 break;
151 }
152 }
153 ptr = ptr->_next;
154 }
155 }
156 }
157 }
158
159 void
run_callbacks(unsigned long long value)160 CallbackList::run_callbacks(unsigned long long value)
161 {
162 void *data;
163 Callback *cb;
164 CallbackListEntry *ptr;
165
166 while (_list && _list->_value <= value)
167 {
168 ptr = _list;
169 _list = ptr->_next;
170 cb = ptr->_cb;
171 data = ptr->_data;
172 delete ptr;
173 if (cb)
174 cb->callback(data);
175 }
176 }
177
178 void
remove_callback_listener(Callback * cb)179 CallbackList::remove_callback_listener(Callback *cb)
180 {
181 CallbackListEntry *ptr = _list;
182
183 for (ptr = _list;ptr != NULL;ptr = ptr->_next)
184 if (ptr->_cb == cb)
185 ptr->_cb = NULL;
186 }
187
188 /*
189 ################################################################################
190 ################################################################################
191 ################################################################################
192 */
193
194 #if 0
195 void _print_callback_list(const char *why, unsigned long long clock,
196 callback_list *list, const char *txt)
197 {
198 int a;
199 callback_list *ptr;
200
201 a = 0;
202 for (ptr = list;ptr != NULL;ptr = ptr->_next) a++;
203 cerr.form("paranoia_check (%s):\n", why);
204 cerr.form("\tfunction = %s\n", txt);
205 cerr.form("\tpc = %04x\n", z80->getPC());
206 cerr.form("\tlength = %10d\n", a);
207 cerr.form("\tdiff = %10Ld\n", list->_counter - clock);
208 cerr.form("\tcounter = %10Ld\n", clock);
209 for (ptr = list;ptr != NULL;ptr = ptr->_next)
210 {
211 cerr.form("\tcounter = %10Ld, cb = %8p [%s], data = %8p\n",
212 ptr->_counter, ptr->_cb, ptr->_cb->get_name(), ptr->_data);
213 }
214 }
215
216 void _callback_paranoia_check(unsigned long long clock, callback_list *list,
217 char *txt)
218 {
219 unsigned long long last = 0;
220 callback_list *tmp;
221 callback_list *ptr = list;
222
223 while (ptr != NULL)
224 {
225 if (ptr->_counter < clock)
226 {
227 _print_callback_list("ptr->counter < clock", clock, list, txt);
228 return;
229 }
230 if (ptr->_counter < last)
231 {
232 _print_callback_list("ptr->counter < last", clock, list, txt);
233 return;
234 }
235
236 tmp = list;
237 while (tmp != ptr)
238 {
239 if (tmp->_counter > ptr->_counter)
240 {
241 _print_callback_list("tmp->counter > ptr->counter",
242 clock, list, txt);
243 return;
244 }
245 tmp = tmp->_next;
246 }
247
248 last = ptr->_counter;
249 ptr = ptr->_next;
250 }
251 }
252 #endif
253
254