Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
callback.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /*************************************************************************
9  *
10  * file: callback.cpp
11  *
12  * =======================================================================
13  *
14  * Description: This file contains the callback facility processing.
15  *
16  * Exported functions:
17  * soar_add_callback
18  * soar_invoke_callbacks
19  * soar_remove_callback
20  *
21  * soar_callback_data_free_string
22  * soar_callback_enum_to_name
23  * soar_callback_name_to_enum
24  *
25  * Each agent has a separate callback table. The table has one entry
26  * per callback type and the entry is a pointer to a list. The list
27  * contains installed callbacks, one callback per list cons cell.
28  *
29  * =======================================================================
30  */
31 
32 #include <stdlib.h>
33 
34 #include "callback.h"
35 #include "agent.h"
36 #include "init_soar.h"
37 #include "print.h"
38 #include "utilities.h"
39 
40 const char * soar_callback_names[] =
41 {
88  //NUMBER_OF_CALLBACKS
89 };
90 
91 void soar_init_callbacks (agent* the_agent)
92 {
93  int ct; // ct was originally of type SOAR_CALLBACK_TYPE, changed for c++ compatibility (5/1/02)
94 
95  for (ct = 1; ct < NUMBER_OF_CALLBACKS; ct++)
96  {
97  the_agent->soar_callbacks[ct] = NIL;
98  }
99 }
100 
101 int callback_count(agent* the_agent, SOAR_CALLBACK_TYPE callback_type)
102 {
103  int count = 0;
104  for (cons * c = the_agent->soar_callbacks[callback_type];
105  c != NIL;
106  c = c->rest)
107  {
108  ++count;
109  }
110 
111  return count;
112 }
113 
114 #include <iostream>
115 void soar_add_callback (agent* thisAgent,
116  SOAR_CALLBACK_TYPE callback_type,
117  soar_callback_fn fn,
118  soar_callback_event_id eventid,
119  soar_callback_data data,
120  soar_callback_free_fn free_fn,
121  soar_callback_id id)
122 {
123 
124  soar_callback * cb;
125 
126  cb = new soar_callback;
127  cb->function = fn;
128  cb->data = data;
129  cb->eventid = eventid ;
130  cb->free_function = free_fn;
131  cb->id = id;
132 
133  push(thisAgent, cb, thisAgent->soar_callbacks[callback_type]);
134 
135  //std::cout << soar_callback_enum_to_name(callback_type, false)
136  // << " (" << callback_count(thisAgent, callback_type) << ")";
137  //if (callback_timers.find(callback_type) == callback_timers.end())
138  //{
139  // callback_timers[callback_type] = soar_timer_accumulator();
140  // std::cout << " created timer";
141  //}
142  //std::cout << std::endl;
143 }
144 
145 //void soar_print_detailed_callback_stats()
146 //{
147 // for (std::map<SOAR_CALLBACK_TYPE, soar_timer_accumulator>::iterator iter = callback_timers.begin();
148 // iter != callback_timers.end(); ++iter)
149 // {
150 // std::cout << soar_callback_enum_to_name(iter->first, false) << ": "
151 // << iter->second.get_sec() << std::endl;
152 // }
153 //}
154 
156 {
157  free(data);
158 }
159 
161  Bool monitorable_only)
162 {
163  int limit;
164 
165  if (monitorable_only)
166  {
168  }
169  else
170  {
171  limit = NUMBER_OF_CALLBACKS;
172  }
173 
174  if ((0 < i) && (i < limit))
175  {
176  return soar_callback_names[i];
177  }
178  return NULL;
179 }
180 
182  Bool monitorable_only)
183 {
184  int limit;
185  int i; // i was originally of type SOAR_CALLBACK_TYPE, changed for c++ compatibility (5/1/02)
186 
187  if (monitorable_only)
188  {
190  }
191  else
192  {
193  limit = NUMBER_OF_CALLBACKS;
194  }
195 
196  for(i = 1; i < limit; i++)
197  {
198  if (!strcmp(name, soar_callback_names[i]))
199  {
200  return static_cast<SOAR_CALLBACK_TYPE>(i);
201  }
202  }
203 
204  return NO_CALLBACK;
205 }
206 
208  SOAR_CALLBACK_TYPE callback_type)
209 {
210  list * cb_cons;
211 
212  cb_cons = the_agent->soar_callbacks[callback_type];
213 
214  if (cb_cons == NULL)
215  {
216  return FALSE;
217  }
218 
219  return TRUE;
220 }
221 
223  SOAR_CALLBACK_TYPE callback_type,
224  soar_callback_id id)
225 {
226  cons * c;
227 
228  for (c = the_agent->soar_callbacks[callback_type];
229  c != NIL;
230  c = c->rest)
231  {
232  soar_callback * cb;
233 
234  cb = static_cast< soar_callback* >(c->first);
235 
236  if (cb->id == id)
237  {
238  return cb;
239  }
240  }
241 
242  return NULL;
243 }
244 
246 {
247  if (cb->free_function)
248  {
249  cb->free_function(cb->data);
250  }
251  delete cb;
252 }
253 
254 // voigtjr: removed inline in an attempt to quell linker error
255 //inline void soar_invoke_callbacks (agent* thisAgent,
256 void soar_invoke_callbacks (agent* thisAgent,
257  SOAR_CALLBACK_TYPE callback_type,
258  soar_call_data call_data)
259 {
260  cons * c; /* we need this if we loop over multiple callback functions */
261 
262 /* if no callback is registered, just return */
263  if (!thisAgent->soar_callbacks[callback_type]) return;
264 
265 /* REW: begin 28.07.96 */
266  /* We want to stop the Soar kernel timers whenever a callback is initiated and
267  keep track of how much time the callbacks take cumulatively. This
268  switch doesn't include every pre-defined callback -- however, it should
269  provide a good "ballpark" estimate because it is focused on all those
270  that occur doing do_one_top_level_phase in init_soar.c.
271 
272  Note that this case will only be compiled if NO_TIMING_STUFF is not
273  defined. So, if you are worried about the performance costs of this case,
274  you can always get rid of it by not including the timing code. */
275 
276 #ifndef NO_TIMING_STUFF
277  switch (callback_type) {
278  /* This case is necssary to make sure we are in one of the decision cycle
279  monitors when the routine is invoked. If so, then we want to turn off
280  the current timers and turn on the appropriate monitor timers. The
281  'appropriate' timer is determined by the current phase. */
282 
286  /* for above three: thisAgent->current_phase = INPUT_PHASE */
289  /* for above two: thisAgent->current_phase = OUTPUT_PHASE */
292  /* for above two: thisAgent->current_phase = PREFERENCE_PHASE soar7 only */
295  /* for above two: thisAgent->current_phase = WM_PHASE soar7 only */
298  /* for above two: thisAgent->current_phase = DECISION_PHASE */
301  /* for above two: thisAgent->current_phase = PROPOSE_PHASE soar8 only */
304  /* for above two: thisAgent->current_phase = APPLY_PHASE soar8 only */
306  /* for soar7: thisAgent->current_phase = DECISION_PHASE; for soar8 it's OUTPUT_PHASE */
307  thisAgent->timers_phase.stop();
308  thisAgent->timers_kernel.stop();
309  thisAgent->timers_total_kernel_time.update(thisAgent->timers_kernel);
310  thisAgent->timers_decision_cycle_phase[thisAgent->current_phase].update(thisAgent->timers_phase);
311  thisAgent->timers_phase.start();
312  break;
314  /* Stop the kernel and phase timers for the input function.
315  * the output function is done in do_output_phase */
316  thisAgent->timers_phase.stop();
317  thisAgent->timers_kernel.stop();
318  thisAgent->timers_total_kernel_time.update(thisAgent->timers_kernel);
319  thisAgent->timers_decision_cycle_phase[thisAgent->current_phase].update(thisAgent->timers_phase);
320  thisAgent->timers_kernel.start();
321  break;
322 
323  default: break;
324  }
325 #endif
326 
327 /* REW: end 28.07.96 */
328 
329 
330  for (c = thisAgent->soar_callbacks[callback_type];
331  c != NIL;
332  c = c->rest)
333  {
334  soar_callback * cb;
335 
336  cb = static_cast< soar_callback* >(c->first);
337  cb->function(thisAgent, cb->eventid, cb->data, call_data);
338  }
339 
340 /* REW: begin 28.07.96 */
341 
342 #ifndef NO_TIMING_STUFF
343  switch (callback_type) {
362  /* for soar7: thisAgent->current_phase = DECISION_PHASE; for soar8 it's OUTPUT_PHASE */
363  thisAgent->timers_phase.stop();
364  thisAgent->timers_monitors_cpu_time[thisAgent->current_phase].update(thisAgent->timers_phase);
365  thisAgent->callback_timers[callback_type].update(thisAgent->timers_phase);
366  thisAgent->timers_kernel.start();
367  thisAgent->timers_phase.start();
368  break;
370  /* Stop input_function_cpu_time timer. Restart kernel and phase timers */
371  thisAgent->timers_kernel.stop();
372  thisAgent->timers_input_function_cpu_time.update(thisAgent->timers_kernel);
373  thisAgent->callback_timers[callback_type].update(thisAgent->timers_kernel);
374  thisAgent->timers_kernel.start();
375  thisAgent->timers_phase.start();
376  break;
377 
378  default: break;
379  }
380 #endif
381 
382 /* REW: end 28.07.96 */
383 
384 }
385 
387  SOAR_CALLBACK_TYPE callback_type,
388  soar_call_data call_data)
389 {
390  list * head;
391 
392  /* if no callback is registered, just return */
393  head = thisAgent->soar_callbacks[callback_type];
394  if (head == NULL) return;
395 
396 /* REW: begin 28.07.96 */
397 
398 #ifndef NO_TIMING_STUFF
399  switch (callback_type) {
403  /* for these three: thisAgent->current_phase = INPUT_PHASE */
406  /* for these two: thisAgent->current_phase = OUTPUT_PHASE */
409  /* for these two: thisAgent->current_phase = PREFERENCE_PHASE */
412  /* for these two: thisAgent->current_phase = WM_PHASE */
415  /* for above two: thisAgent->current_phase = DECISION_PHASE */
418  /* for above two: thisAgent->current_phase = PROPOSE_PHASE soar8 only */
421  /* for above two: thisAgent->current_phase = APPLY_PHASE soar8 only */
423  /* for soar7: thisAgent->current_phase = DECISION_PHASE; for soar8 it's OUTPUT_PHASE */
424  thisAgent->timers_phase.stop();
425  thisAgent->timers_kernel.stop();
426  thisAgent->timers_total_kernel_time.update(thisAgent->timers_kernel);
427  thisAgent->timers_decision_cycle_phase[thisAgent->current_phase].update(thisAgent->timers_phase);
428  thisAgent->timers_phase.start();
429  break;
431  /* Stop the kernel and phase timers for the input function.
432  * the output function is done in do_output_phase */
433  thisAgent->timers_phase.stop();
434  thisAgent->timers_kernel.stop();
435  thisAgent->timers_total_kernel_time.update(thisAgent->timers_kernel);
436  thisAgent->timers_decision_cycle_phase[thisAgent->current_phase].update(thisAgent->timers_phase);
437  thisAgent->timers_kernel.start();
438  break;
439  default: break;
440  }
441 #endif
442 
443 /* REW: end 28.07.96 */
444 
445  soar_callback * cb;
446 
447  cb = static_cast< soar_callback* >(head->first);
448  cb->function(thisAgent, cb->eventid, cb->data, call_data);
449 
450 
451 /* REW: begin 28.07.96 */
452 
453 #ifndef NO_TIMING_STUFF
454  switch (callback_type) {
471  thisAgent->timers_phase.stop();
472  thisAgent->timers_monitors_cpu_time[thisAgent->current_phase].update(thisAgent->timers_phase);
473  thisAgent->callback_timers[callback_type].update(thisAgent->timers_phase);
474  thisAgent->timers_kernel.start();
475  thisAgent->timers_phase.start();
476  break;
478  /* Stop input_function_cpu_time timer. Restart kernel and phase timers */
479  thisAgent->timers_kernel.stop();
480  thisAgent->timers_input_function_cpu_time.update(thisAgent->timers_kernel);
481  thisAgent->callback_timers[callback_type].update(thisAgent->timers_kernel);
482  thisAgent->timers_kernel.start();
483  thisAgent->timers_phase.start();
484  break;
485 
486  default: break;
487  }
488 #endif
489 
490 /* REW: end 28.07.96 */
491 
492 }
493 
495  Bool monitorable_only)
496 {
497  int limit;
498  int ct; // ct was originally of type SOAR_CALLBACK_TYPE, changed for c++ compatibility (5/1/02)
499 
500  if (monitorable_only)
501  {
503  }
504  else
505  {
506  limit = NUMBER_OF_CALLBACKS;
507  }
508 
509  for (ct = 1; ct < limit; ct++)
510  {
511  print(thisAgent, "%s: ", soar_callback_enum_to_name(static_cast<SOAR_CALLBACK_TYPE>(ct), FALSE));
512  soar_list_all_callbacks_for_event (thisAgent, static_cast<SOAR_CALLBACK_TYPE>(ct));
513  print(thisAgent, "\n");
514  }
515 }
516 
519 {
520  cons * c;
521 
522  for (c = thisAgent->soar_callbacks[ct];
523  c != NIL;
524  c = c->rest)
525  {
526  soar_callback * cb;
527 
528  cb = static_cast< soar_callback* >(c->first);
529 
530  print(thisAgent, "%s ", cb->id.c_str());
531  }
532 }
533 
534 void soar_pop_callback (agent* thisAgent,
535  SOAR_CALLBACK_TYPE callback_type)
536 {
537  list * head;
538  soar_callback * cb;
539 
540  head = thisAgent->soar_callbacks[callback_type];
541 
542  if (head == NULL)
543  {
544  print_string(thisAgent, "Attempt to remove non-existant callback.\n");
545  return;
546  }
547 
548  if ( (callback_type == PRINT_CALLBACK)
549  && (head->rest == NULL))
550  {
551  print_string(thisAgent, "Attempt to remove last print callback. Ignored.\n");
552  return;
553  }
554 
555  cb = static_cast< soar_callback* >(head->first);
556 
557  thisAgent->soar_callbacks[callback_type] = head->rest;
559  free_cons(thisAgent, head);
560 }
561 
562 void soar_push_callback (agent* thisAgent,
563  SOAR_CALLBACK_TYPE callback_type,
564  soar_callback_fn fn,
565  soar_callback_event_id eventid,
566  soar_callback_data data,
567  soar_callback_free_fn free_fn)
568 {
569  soar_callback * cb;
570 
571  cb = new soar_callback;
572  cb->function = fn;
573  cb->data = data;
574  cb->eventid = eventid ;
575  cb->free_function = free_fn;
576  //cb->id initialized to empty string
577 
578  push(thisAgent, cb, thisAgent->soar_callbacks[callback_type]);
579 }
580 
582 {
583  int ct; // ct was originally of type SOAR_CALLBACK_TYPE, changed for c++ compatibility (5/1/02)
584 
585  for (ct = 1; ct < NUMBER_OF_MONITORABLE_CALLBACKS; ct++)
586  {
587  soar_remove_all_callbacks_for_event (thisAgent, static_cast<SOAR_CALLBACK_TYPE>(ct));
588  }
589 }
590 
593 {
594  cons * c;
595  list * next;
596 
597  next = thisAgent->soar_callbacks[ct];
598 
599  for (c = next; c != NIL; c = next)
600  {
601  soar_callback * cb;
602 
603  cb = static_cast< soar_callback* >(c->first);
604 
605  next = next->rest;
607  free_cons(thisAgent, c);
608  }
609 
610  thisAgent->soar_callbacks[ct] = NIL;
611 }
612 
613 void soar_remove_callback (agent* thisAgent,
614  SOAR_CALLBACK_TYPE callback_type,
615  soar_callback_id id)
616 {
617  cons * c;
618  cons * prev_c = NULL; /* Initialized to placate gcc -Wall */
619  list * head;
620 
621  head = thisAgent->soar_callbacks[callback_type];
622 
623  for (c = head; c != NIL; c = c->rest)
624  {
625  soar_callback * cb;
626 
627  cb = static_cast< soar_callback* >(c->first);
628 
629  if (cb->id == id)
630  {
631  if (c != head)
632  {
633  prev_c->rest = c->rest;
635  free_cons(thisAgent, c);
636  return;
637  }
638  else
639  {
640  thisAgent->soar_callbacks[callback_type] = head->rest;
642  free_cons(thisAgent, c);
643  return;
644  }
645  }
646  prev_c = c;
647  }
648 }
649 
650 void soar_callback_test_callback (agent* /*the_agent*/,
651  soar_callback_data data,
652  soar_call_data /*call_data*/)
653 {
654  printf("%s test callback executed.\n", static_cast<char *>(data));
655 }
656 
657 
659 {
660  int i; // i was originally of type SOAR_CALLBACK_TYPE, changed for c++ compatibility (5/1/02)
661  static const char * test_callback_name = "test";
662 
663  for(i = 1; i < NUMBER_OF_MONITORABLE_CALLBACKS; i++)
664  {
665  soar_add_callback(thisAgent, static_cast<SOAR_CALLBACK_TYPE>(i),
666  reinterpret_cast<soar_callback_fn>(soar_callback_test_callback), i,
667  static_cast<void*>(const_cast<char*>(soar_callback_enum_to_name(static_cast<SOAR_CALLBACK_TYPE>(i), TRUE))),
668  NULL, test_callback_name);
669  }
670 }
671