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