Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

callback.c

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  file:  callback.c
00004  *
00005  * =======================================================================
00006  *
00007  * Description: This file contains the callback facility processing.  
00008  * 
00009  * Exported functions:
00010  *   soar_add_callback
00011  *   soar_invoke_callbacks
00012  *   soar_remove_callback
00013  *
00014  *   soar_callback_data_free_string
00015  *   soar_callback_enum_to_name
00016  *
00017  * Each agent has a separate callback table.  The table has one entry
00018  * per callback type and the entry is a pointer to a list.  The list
00019  * contains installed callbacks, one callback per list cons cell.
00020  *
00021  * =======================================================================
00022  *
00023  * Copyright 1995-2003 Carnegie Mellon University,
00024  *                                                                               University of Michigan,
00025  *                                                                               University of Southern California/Information
00026  *                                                                               Sciences Institute. All rights reserved.
00027  *                                                                              
00028  * Redistribution and use in source and binary forms, with or without
00029  * modification, are permitted provided that the following conditions are met:
00030  *
00031  * 1.   Redistributions of source code must retain the above copyright notice,
00032  *              this list of conditions and the following disclaimer. 
00033  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00034  *              this list of conditions and the following disclaimer in the documentation
00035  *              and/or other materials provided with the distribution. 
00036  *
00037  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00038  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00039  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00040  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00041  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00042  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00043  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00044  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00045  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00046  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00047  * The views and conclusions contained in the software and documentation are
00048  * those of the authors and should not be interpreted as representing official
00049  * policies, either expressed or implied, of Carnegie Mellon University, the
00050  * University of Michigan, the University of Southern California/Information
00051  * Sciences Institute, or the Soar consortium.
00052  * =======================================================================
00053  */
00054 
00055 #include "soarkernel.h"
00056 #include "soar_core_api.h"
00057 #include "callback.h"
00058 
00059 extern soar_global_callback_array soar_global_callbacks;
00060 extern unsigned long soar_global_callback_error;
00061 
00062 char *soar_callback_names[] = { /* Must match order of       */
00063     "none",                     /* SOAR_CALLBACK_TYPE        */
00064     "system-startup",
00065     "system-termination",
00066     "before-init-soar",
00067     "after-init-soar",
00068     "after-halt-soar",
00069     "before-schedule-cycle",
00070     "after-schedule-cycle",
00071     "before-decision-cycle",
00072     "after-decision-cycle",
00073     "before-input-phase",
00074     "input-phase-cycle",
00075     "after-input-phase",
00076     "before-preference-phase-cycle",
00077     "after-preference-phase-cycle",
00078     "before-wm-phase-cycle",
00079     "after-wm-phase-cycle",
00080     "before-output-phase",
00081     "output-phase",
00082     "after-output-phase",
00083     "before-decision-phase-cycle",
00084     "after-decision-phase-cycle",
00085     "wm-changes",
00086     "create-new-context",
00087     "pop-context-stack",
00088     "create-new-attribute-impasse",
00089     "remove-attribute-impasse",
00090     "production-just-added",
00091     "production-just-about-to-be-excised",
00092     "firing",
00093     "retraction",
00094     "system-parameter-changed",
00095     "print",
00096     "log",
00097     "ask"
00098 #ifdef ATTENTION_LAPSE
00099         "init-lapse-duration"
00100 #endif
00101         /*  "read",   *//* kjh CUSP B10 */
00102         /*  "record", *//* kjh CUSP B10 */
00103         /* Nothing corresponds to NUMBER_OF_CALLBACKS */
00104 };
00105 
00106 void soar_init_callbacks(soar_callback_agent the_agent)
00107 {
00108     SOAR_CALLBACK_TYPE ct;
00109 
00110     for (ct = 1; ct < NUMBER_OF_CALLBACKS; ct++) {
00111         ((agent *) the_agent)->soar_callbacks[ct] = (list *) NIL;
00112     }
00113     ((agent *) the_agent)->callback_error = 0;
00114 }
00115 
00116 void soar_init_global_callbacks(void)
00117 {
00118     SOAR_GLOBAL_CALLBACK_TYPE gct;
00119 
00120     for (gct = 1; gct < NUMBER_OF_GLOBAL_CALLBACKS; gct++) {
00121         soar_global_callbacks[gct] = (list *) NIL;
00122     }
00123 }
00124 
00125 void soar_callback_data_free_string(soar_callback_data data)
00126 {
00127     free((char *) data);
00128 }
00129 
00130 char *soar_callback_enum_to_name(SOAR_CALLBACK_TYPE i, bool monitorable_only)
00131 {
00132     int limit;
00133 
00134     if (monitorable_only) {
00135         limit = NUMBER_OF_MONITORABLE_CALLBACKS;
00136     } else {
00137         limit = NUMBER_OF_CALLBACKS;
00138     }
00139 
00140     if ((0 < i) && (i < limit)) {
00141         return soar_callback_names[i];
00142     }
00143     return NULL;
00144 }
00145 
00146 bool soar_exists_callback(soar_callback_agent the_agent, SOAR_CALLBACK_TYPE callback_type)
00147 {
00148     list *cb_cons;
00149 
00150     if ((agent *) the_agent == NULL)
00151         return FALSE;
00152 
00153     cb_cons = ((agent *) the_agent)->soar_callbacks[callback_type];
00154 
00155     if (cb_cons == NULL) {
00156         return FALSE;
00157     }
00158 
00159     return TRUE;
00160 }
00161 
00162 soar_callback *soar_exists_callback_id(soar_callback_agent the_agent,
00163                                        SOAR_CALLBACK_TYPE callback_type, soar_callback_id id)
00164 {
00165     cons *c;
00166 
00167     if ((agent *) the_agent == NULL)
00168         return FALSE;
00169 
00170     for (c = ((agent *) the_agent)->soar_callbacks[callback_type]; c != NIL; c = c->rest) {
00171         soar_callback *cb;
00172 
00173         cb = (soar_callback *) c->first;
00174 
00175         if (!strcmp(cb->id, id)) {
00176             return cb;
00177         }
00178     }
00179 
00180     return NULL;
00181 }
00182 
00183 void soar_destroy_callback(soar_callback * cb)
00184 {
00185     if (cb->id) {
00186         free((char *) cb->id);
00187     }
00188     if (cb->free_function) {
00189         cb->free_function(cb->data);
00190     }
00191     free((void *) cb);
00192 }
00193 
00194 void soar_invoke_callbacks(soar_callback_agent the_agent, SOAR_CALLBACK_TYPE callback_type, soar_call_data call_data)
00195 {
00196     cons *c;
00197 
00198 /* REW: begin 28.07.96 */
00199     /* We want to stop the Soar kernel timers whenever a callback is initiated and
00200        keep track of how much time the callbacks take cumulatively. This 
00201        switch doesn't include every pre-defined callback -- however, it should 
00202        provide a good "ballpark" estimate because it is focused on all those
00203        that occur doing do_one_top_level_phase in init_soar.c.
00204 
00205        Note that this case will only be compiled if NO_TIMING_STUFF is   not 
00206        defined.  So, if you are worried about the performance costs of this case,
00207        you can always get rid of it by not including the timing code. */
00208 
00209 #ifndef NO_TIMING_STUFF
00210     switch (callback_type) {
00211         /* This case is necssary to make sure we are in one of the decision cycle
00212            monitors when the routine is invoked.  If so, then we want to turn off
00213            the current timers and turn on the appropriate monitor timers.  The 
00214            'appropriate' timer is determined by the current phase.  */
00215 
00216 #ifndef FEW_CALLBACKS
00217 
00218     case BEFORE_DECISION_CYCLE_CALLBACK:
00219     case BEFORE_INPUT_PHASE_CALLBACK:
00220     case AFTER_INPUT_PHASE_CALLBACK:
00221         /* for these three: current_agent(current_phase) = INPUT_PHASE */
00222     case BEFORE_OUTPUT_PHASE_CALLBACK:
00223     case AFTER_OUTPUT_PHASE_CALLBACK:
00224         /* for these two: current_agent(current_phase) = OUTPUT_PHASE */
00225     case BEFORE_PREFERENCE_PHASE_CALLBACK:
00226     case AFTER_PREFERENCE_PHASE_CALLBACK:
00227         /* for these two: current_agent(current_phase) = PREFERENCE_PHASE */
00228     case BEFORE_WM_PHASE_CALLBACK:
00229     case AFTER_WM_PHASE_CALLBACK:
00230         /* for these two: current_agent(current_phase) = WM_PHASE */
00231     case BEFORE_DECISION_PHASE_CALLBACK:
00232     case AFTER_DECISION_PHASE_CALLBACK:
00233 #endif
00234 
00235 #ifndef NO_ADC_CALLBACK
00236     case AFTER_DECISION_CYCLE_CALLBACK:
00237 
00238 #ifndef KERNEL_TIME_ONLY
00239         /* for these three: current_agent(current_phase) = DECISION_PHASE */
00240 
00241         stop_timer(&current_agent(start_phase_tv),
00242                    &current_agent(decision_cycle_phase_timers[current_agent(current_phase)]));
00243 #endif
00244 
00245         stop_timer(&current_agent(start_kernel_tv), &current_agent(total_kernel_time));
00246 #ifndef KERNEL_TIME_ONLY
00247         start_timer(&current_agent(start_phase_tv));
00248 #endif
00249         break;
00250 
00251 #endif
00252 
00253 #ifndef NO_IO_CALLBACKS
00254     case INPUT_PHASE_CALLBACK:
00255         /* Stop the kernel and phase timers for the input function */
00256 
00257 #ifndef KERNEL_TIME_ONLY
00258         stop_timer(&current_agent(start_phase_tv),
00259                    &current_agent(decision_cycle_phase_timers[current_agent(current_phase)]));
00260 #endif
00261 
00262         stop_timer(&current_agent(start_kernel_tv), &current_agent(total_kernel_time));
00263         start_timer(&current_agent(start_kernel_tv));
00264         break;
00265 #endif
00266     default:
00267         break;
00268 
00269     }
00270 
00271 #endif
00272 
00273 /* REW: end 28.07.96 */
00274     for (c = ((agent *) the_agent)->soar_callbacks[callback_type]; c != NIL; c = c->rest) {
00275         soar_callback *cb;
00276 
00277         cb = (soar_callback *) c->first;
00278         cb->function(the_agent, cb->data, call_data);
00279     }
00280 
00281 /* REW: begin 28.07.96 */
00282 
00283 #ifndef NO_TIMING_STUFF
00284     switch (callback_type) {
00285 
00286 #ifndef FEW_CALLBACKS
00287 
00288     case BEFORE_DECISION_CYCLE_CALLBACK:
00289     case BEFORE_INPUT_PHASE_CALLBACK:
00290     case AFTER_INPUT_PHASE_CALLBACK:
00291     case BEFORE_OUTPUT_PHASE_CALLBACK:
00292     case AFTER_OUTPUT_PHASE_CALLBACK:
00293     case BEFORE_PREFERENCE_PHASE_CALLBACK:
00294     case AFTER_PREFERENCE_PHASE_CALLBACK:
00295     case BEFORE_WM_PHASE_CALLBACK:
00296     case AFTER_WM_PHASE_CALLBACK:
00297     case BEFORE_DECISION_PHASE_CALLBACK:
00298     case AFTER_DECISION_PHASE_CALLBACK:
00299 #endif
00300 
00301 #ifndef NO_ADC_CALLBACK
00302 
00303     case AFTER_DECISION_CYCLE_CALLBACK:
00304 
00305 #ifndef KERNEL_TIME_ONLY
00306         stop_timer(&current_agent(start_phase_tv), &current_agent(monitors_cpu_time[current_agent(current_phase)]));
00307 #endif
00308 
00309         start_timer(&current_agent(start_kernel_tv));
00310 #ifndef KERNEL_TIME_ONLY
00311         start_timer(&current_agent(start_phase_tv));
00312 #endif
00313         break;
00314 
00315 #endif
00316 
00317 #ifndef NO_IO_CALLBACKS
00318     case INPUT_PHASE_CALLBACK:
00319         /* Stop input_function_cpu_time timer.  Restart kernel and phase timers */
00320         stop_timer(&current_agent(start_kernel_tv), &current_agent(input_function_cpu_time));
00321         start_timer(&current_agent(start_kernel_tv));
00322 #ifndef KERNEL_TIME_ONLY
00323         start_timer(&current_agent(start_phase_tv));
00324 #endif
00325         break;
00326 #endif
00327     default:
00328         break;
00329 
00330     }
00331 
00332 #endif
00333 
00334 /* REW: end 28.07.96 */
00335 
00336 }
00337 
00338 void soar_invoke_first_callback(soar_callback_agent the_agent,
00339                                 SOAR_CALLBACK_TYPE callback_type, soar_call_data call_data)
00340 {
00341     list *head;
00342 
00343 /* REW: begin 28.07.96 */
00344 
00345 #ifndef NO_TIMING_STUFF
00346     switch (callback_type) {
00347 
00348 #ifndef FEW_CALLBACKS
00349 
00350     case BEFORE_DECISION_CYCLE_CALLBACK:
00351     case BEFORE_INPUT_PHASE_CALLBACK:
00352     case AFTER_INPUT_PHASE_CALLBACK:
00353         /* for these three: current_agent(current_phase) = INPUT_PHASE */
00354     case BEFORE_OUTPUT_PHASE_CALLBACK:
00355     case AFTER_OUTPUT_PHASE_CALLBACK:
00356         /* for these two: current_agent(current_phase) = OUTPUT_PHASE */
00357     case BEFORE_PREFERENCE_PHASE_CALLBACK:
00358     case AFTER_PREFERENCE_PHASE_CALLBACK:
00359         /* for these two: current_agent(current_phase) = PREFERENCE_PHASE */
00360     case BEFORE_WM_PHASE_CALLBACK:
00361     case AFTER_WM_PHASE_CALLBACK:
00362         /* for these two: current_agent(current_phase) = WM_PHASE */
00363     case BEFORE_DECISION_PHASE_CALLBACK:
00364     case AFTER_DECISION_PHASE_CALLBACK:
00365 
00366 #endif
00367 
00368 #ifndef NO_ADC_CALLBACK
00369     case AFTER_DECISION_CYCLE_CALLBACK:
00370         /* for these three: current_agent(current_phase) = DECISION_PHASE */
00371 
00372 #ifndef KERNEL_TIME_ONLY
00373         stop_timer(&current_agent(start_phase_tv),
00374                    &current_agent(decision_cycle_phase_timers[current_agent(current_phase)]));
00375 #endif
00376         stop_timer(&current_agent(start_kernel_tv), &current_agent(total_kernel_time));
00377 #ifndef KERNEL_TIME_ONLY
00378         start_timer(&current_agent(start_phase_tv));
00379 #endif
00380         break;
00381 #endif
00382 
00383 #ifndef NO_IO_CALLBACKS
00384     case INPUT_PHASE_CALLBACK:
00385         /* Stop the kernel and phase timers for the input function */
00386 
00387 #ifndef KERNEL_TIME_ONLY
00388         stop_timer(&current_agent(start_phase_tv),
00389                    &current_agent(decision_cycle_phase_timers[current_agent(current_phase)]));
00390 #endif
00391 
00392         stop_timer(&current_agent(start_kernel_tv), &current_agent(total_kernel_time));
00393         start_timer(&current_agent(start_kernel_tv));
00394         break;
00395 #endif
00396     default:
00397         break;
00398 
00399     }
00400 
00401 #endif
00402 /* REW: end 28.07.96 */
00403 
00404     head = ((agent *) the_agent)->soar_callbacks[callback_type];
00405 
00406     if (head != NULL) {
00407         soar_callback *cb;
00408 
00409         cb = (soar_callback *) head->first;
00410         cb->function(the_agent, cb->data, call_data);
00411     }
00412 
00413 /* REW: begin 28.07.96 */
00414 
00415 #ifndef NO_TIMING_STUFF
00416     switch (callback_type) {
00417 
00418 #ifndef FEW_CALLBACKS
00419 
00420     case BEFORE_DECISION_CYCLE_CALLBACK:
00421     case BEFORE_INPUT_PHASE_CALLBACK:
00422     case AFTER_INPUT_PHASE_CALLBACK:
00423     case BEFORE_OUTPUT_PHASE_CALLBACK:
00424     case AFTER_OUTPUT_PHASE_CALLBACK:
00425     case BEFORE_PREFERENCE_PHASE_CALLBACK:
00426     case AFTER_PREFERENCE_PHASE_CALLBACK:
00427     case BEFORE_WM_PHASE_CALLBACK:
00428     case AFTER_WM_PHASE_CALLBACK:
00429     case BEFORE_DECISION_PHASE_CALLBACK:
00430     case AFTER_DECISION_PHASE_CALLBACK:
00431 
00432 #endif
00433 #ifndef NO_ADC_CALLBACK
00434     case AFTER_DECISION_CYCLE_CALLBACK:
00435 #ifndef KERNEL_TIME_ONLY
00436         stop_timer(&current_agent(start_phase_tv), &current_agent(monitors_cpu_time[current_agent(current_phase)]));
00437 #endif
00438         start_timer(&current_agent(start_kernel_tv));
00439 #ifndef KERNEL_TIME_ONLY
00440         start_timer(&current_agent(start_phase_tv));
00441 #endif
00442         break;
00443 #endif
00444 
00445 #ifndef NO_IO_CALLBACKS
00446     case INPUT_PHASE_CALLBACK:
00447         /* Stop input_function_cpu_time timer.  Restart kernel and phase timers */
00448         stop_timer(&current_agent(start_kernel_tv), &current_agent(input_function_cpu_time));
00449         start_timer(&current_agent(start_kernel_tv));
00450 #ifndef KERNEL_TIME_ONLY
00451         start_timer(&current_agent(start_phase_tv));
00452 #endif
00453         break;
00454 #endif
00455     default:
00456         break;
00457 
00458     }
00459 
00460 #endif
00461 
00462 /* REW: end 28.07.96 */
00463 
00464 }
00465 
00466 bool soar_exists_global_callback(SOAR_GLOBAL_CALLBACK_TYPE callback_type)
00467 {
00468     list *cb_cons;
00469 
00470     cb_cons = soar_global_callbacks[callback_type];
00471 
00472     if (cb_cons == NULL) {
00473         return FALSE;
00474     }
00475 
00476     return TRUE;
00477 }
00478 
00479 void soar_invoke_global_callbacks(soar_callback_agent a, SOAR_CALLBACK_TYPE callback_type, soar_call_data call_data)
00480 {
00481     cons *c;
00482 
00483     /* So far, there's no need to mess with the timers, becuase
00484      * we have only implemented function which get called at 
00485      * agent creation and destruction
00486      */
00487 
00488     for (c = soar_global_callbacks[callback_type]; c != NIL; c = c->rest) {
00489         soar_callback *cb;
00490 
00491         cb = (soar_callback *) c->first;
00492         cb->function(a, cb->data, call_data);
00493     }
00494 
00495 }

Generated on Thu Dec 11 13:00:14 2003 for Soar Kernel by doxygen 1.3.5