Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
wmem.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: wmem.cpp
11  *
12  * =======================================================================
13  * These are the working memory management routines and utility functions
14  * for Soar working memory elements.
15  * =======================================================================
16  */
17 
18 /* ======================================================================
19  Working memory routines for Soar 6
20  ====================================================================== */
21 
22 /* Debugging stuff: #define DEBUG_WMES to get slot printouts */
23 
24 //#define DEBUG_WMES
25 
26 #include <stdlib.h>
27 
28 #include "wmem.h"
29 #include "kernel.h"
30 #include "agent.h"
31 #include "gdatastructs.h"
32 #include "symtab.h"
33 #include "decide.h"
34 #include "io_soar.h"
35 #include "rete.h"
36 #include "print.h"
37 #include "tempmem.h"
38 #include "xml.h"
39 #include "soar_TraceNames.h"
40 
41 #include "wma.h"
42 #include "episodic_memory.h"
43 
44 using namespace soar_TraceNames;
45 
46 /* ======================================================================
47 
48  Working Memory Management and Utility Routines
49 
50  Reset_wme_timetags() resets the wme timetag generator back to 1.
51  This should be called during an init-soar.
52 
53  Make_wme() creates and returns a new wme. The caller should add the
54  wme onto the appropriate dll (e.g., my_slot->wmes) and should call
55  add_wme_to_wm() on it.
56 
57  Add_wme_to_wm() and remove_wme_from_wm() make changes to WM. Again,
58  the caller is responsible for manipulating the appropriate dll. WM
59  changes don't actually get stuffed down the rete until the end of the
60  phase, when do_buffered_wm_changes() gets be called.
61 
62  Remove_wme_list_from_wm() is a utility routine that scans through a
63  list of wmes, linked by their "next" fields, and calls remove_wme_from_wm()
64  on each one.
65 
66  Deallocate_wme() deallocates a wme. This should only be invoked via
67  the wme_remove_ref() macro.
68 
69  Find_name_of_object() is a utility function for finding the value of
70  the ^name attribute on a given object (Symbol). It returns the name,
71  or NIL if the object has no name.
72 ====================================================================== */
73 
74 void reset_wme_timetags (agent* thisAgent) {
75  if (thisAgent->num_existing_wmes != 0) {
76  print (thisAgent, "Internal warning: wanted to reset wme timetag generator, but\n");
77  print (thisAgent, "there are still some wmes allocated. (Probably a memory leak.)\n");
78  print (thisAgent, "(Leaving timetag numbers alone.)\n");
79  xml_generate_warning(thisAgent, "Internal warning: wanted to reset wme timetag generator, but\nthere are still some wmes allocated. (Probably a memory leak.)\n(Leaving timetag numbers alone.)");
80  return;
81  }
82  thisAgent->current_wme_timetag = 1;
83 }
84 
85 wme *make_wme (agent* thisAgent, Symbol *id, Symbol *attr, Symbol *value, Bool acceptable)
86 {
87  wme *w;
88 
89  thisAgent->num_existing_wmes++;
90  allocate_with_pool (thisAgent, &thisAgent->wme_pool, &w);
91  w->id = id;
92  w->attr = attr;
93  w->value = value;
94  symbol_add_ref (id);
95  symbol_add_ref (attr);
96  symbol_add_ref (value);
97  w->acceptable = acceptable;
98  w->timetag = thisAgent->current_wme_timetag++;
99  w->reference_count = 0;
100  w->preference = NIL;
101  w->output_link = NIL;
102  w->grounds_tc = 0;
103  w->potentials_tc = 0;
104  w->locals_tc = 0;
105 
106  w->next = NIL;
107  w->prev = NIL;
108  w->rete_next = NIL;
109  w->rete_prev = NIL;
110 
111 /* REW: begin 09.15.96 */
112  /* When we first create a WME, it had no gds value.
113  Do this for ALL wmes, regardless of the operand mode, so that no undefined pointers
114  are floating around. */
115  w->gds = NIL;
116  w->gds_prev = NIL;
117  w->gds_next = NIL;
118 /* REW: end 09.15.96 */
119 
120  w->wma_decay_el = NIL;
121  w->wma_tc_value = 0;
122 
124  w->epmem_valid = NIL;
125 
126  return w;
127 }
128 
129 /* --- lists of buffered WM changes --- */
130 
131 void add_wme_to_wm (agent* thisAgent, wme *w)
132 {
136 
137  push (thisAgent, w, thisAgent->wmes_to_add);
138  if (w->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
139  {
140  post_link_addition (thisAgent, w->id, w->value);
141  if (w->attr == thisAgent->operator_symbol)
142  {
143  w->value->id.isa_operator++;
144  }
145  }
146 }
147 
148 void remove_wme_from_wm (agent* thisAgent, wme *w)
149 {
150  push (thisAgent, w, thisAgent->wmes_to_remove);
151 
152  if (w->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
153  {
154  post_link_removal (thisAgent, w->id, w->value);
155  if (w->attr==thisAgent->operator_symbol)
156  {
157  /* Do this afterward so that gSKI can know that this is an operator */
158  w->value->id.isa_operator--;
159  }
160  }
161 
162  /* REW: begin 09.15.96 */
163  /* When we remove a WME, we always have to determine if it's on a GDS, and, if
164  so, after removing the WME, if there are no longer any WMEs on the GDS,
165  then we can free the GDS memory */
166  if (w->gds)
167  {
168  fast_remove_from_dll(w->gds->wmes_in_gds, w, wme, gds_next, gds_prev);
169  /* printf("\nRemoving WME on some GDS"); */
170 
171  if (!w->gds->wmes_in_gds)
172  {
173  if (w->gds->goal) w->gds->goal->id.gds = NIL;
174  free_with_pool( &( thisAgent->gds_pool ), w->gds );
175  /* printf("REMOVING GDS FROM MEMORY. \n"); */
176  }
177  }
178  /* REW: end 09.15.96 */
179 }
180 
181 void remove_wme_list_from_wm (agent* thisAgent, wme *w, bool updateWmeMap)
182 {
183  wme *next_w;
184 
185  while (w)
186  {
187  next_w = w->next;
188 
189  if (updateWmeMap)
190  {
191  soar_invoke_callbacks( thisAgent, INPUT_WME_GARBAGE_COLLECTED_CALLBACK, static_cast< soar_call_data >( w ) );
192  //remove_wme_from_wmeMap (thisAgent, w);
193  }
194  remove_wme_from_wm (thisAgent, w);
195 
196  w = next_w;
197  }
198 }
199 
200 void do_buffered_wm_changes (agent* thisAgent)
201 {
202  cons *c, *next_c, *cr;
203  wme *w;
204  /*
205  void filtered_print_wme_add(wme *w), filtered_print_wme_remove(wme *w);
206  */
207 
208 #ifndef NO_TIMING_STUFF
209 #ifdef DETAILED_TIMING_STATS
210  soar_process_timer local_timer;
211  local_timer.set_enabled( &( thisAgent->sysparams[ TIMERS_ENABLED ] ) );
212 #endif
213 #endif
214 
215  /* --- if no wme changes are buffered, do nothing --- */
216  if (!thisAgent->wmes_to_add && !thisAgent->wmes_to_remove) return;
217 
218  /* --- call output module in case any changes are output link changes --- */
219  inform_output_module_of_wm_changes (thisAgent, thisAgent->wmes_to_add,
220  thisAgent->wmes_to_remove);
221 
222  /* --- invoke callback routine. wmes_to_add and wmes_to_remove can --- */
223  /* --- be fetched from the agent structure. --- */
225 
226  /* --- stuff wme changes through the rete net --- */
227 #ifndef NO_TIMING_STUFF
228 #ifdef DETAILED_TIMING_STATS
229  local_timer.start();
230 #endif
231 #endif
232  for (c=thisAgent->wmes_to_add; c!=NIL; c=c->rest)
233  {
234  add_wme_to_rete (thisAgent, static_cast<wme_struct *>(c->first));
235  }
236  for (c=thisAgent->wmes_to_remove; c!=NIL; c=c->rest)
237  {
238  remove_wme_from_rete (thisAgent, static_cast<wme_struct *>(c->first));
239  }
240 #ifndef NO_TIMING_STUFF
241 #ifdef DETAILED_TIMING_STATS
242  local_timer.stop();
243  thisAgent->timers_match_cpu_time[thisAgent->current_phase].update(local_timer);
244 #endif
245 #endif
246  /* --- warn if watching wmes and same wme was added and removed -- */
247  if (thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM]) {
248  for (c=thisAgent->wmes_to_add; c!=NIL; c=next_c) {
249  next_c = c->rest;
250  w = static_cast<wme_struct *>(c->first);
251  for (cr=thisAgent->wmes_to_remove; cr!=NIL; cr=next_c) {
252  next_c = cr->rest;
253  if (w == cr->first) {
254  const char * const kWarningMessage = "WARNING: WME added and removed in same phase : ";
255  print (thisAgent, const_cast< char* >( kWarningMessage) );
256  xml_begin_tag( thisAgent, kTagWarning );
257  xml_att_val( thisAgent, kTypeString, kWarningMessage );
258  print_wme(thisAgent, w);
259  xml_end_tag( thisAgent, kTagWarning );
260  }
261  }
262  }
263  }
264 
265 
266  /* --- do tracing and cleanup stuff --- */
267  for (c=thisAgent->wmes_to_add; c!=NIL; c=next_c) {
268  next_c = c->rest;
269  w = static_cast<wme_struct *>(c->first);
270  if (thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM]) {
271  /* print ("=>WM: ");
272  * print_wme (w);
273  */
274  filtered_print_wme_add(thisAgent, w); /* kjh(CUSP-B2) begin */
275  }
276 
277  wme_add_ref (w);
278  free_cons (thisAgent, c);
279  thisAgent->wme_addition_count++;
280  }
281  for (c=thisAgent->wmes_to_remove; c!=NIL; c=next_c) {
282  next_c = c->rest;
283  w = static_cast<wme_struct *>(c->first);
284  if (thisAgent->sysparams[TRACE_WM_CHANGES_SYSPARAM]) {
285  /* print ("<=WM: ");
286  * print_wme (thisAgent, w);
287  */
288  filtered_print_wme_remove (thisAgent, w); /* kjh(CUSP-B2) begin */
289  }
290 
291  wme_remove_ref (thisAgent, w);
292  free_cons (thisAgent, c);
293  thisAgent->wme_removal_count++;
294  }
295  thisAgent->wmes_to_add = NIL;
296  thisAgent->wmes_to_remove = NIL;
297 }
298 
299 void deallocate_wme (agent* thisAgent, wme *w) {
300 #ifdef DEBUG_WMES
301  print_with_symbols (thisAgent, "\nDeallocate wme: ");
302  print_wme (thisAgent, w);
303 #endif
304 
305  if ( wma_enabled( thisAgent ) )
306  {
307  wma_remove_decay_element( thisAgent, w );
308  }
309 
310  symbol_remove_ref (thisAgent, w->id);
311  symbol_remove_ref (thisAgent, w->attr);
312  symbol_remove_ref (thisAgent, w->value);
313  free_with_pool (&thisAgent->wme_pool, w);
314  thisAgent->num_existing_wmes--;
315 }
316 
317 Symbol *find_name_of_object (agent* thisAgent, Symbol *object) {
318  slot *s;
319 
320  if (object->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) return NIL;
321  s = find_slot (object, thisAgent->name_symbol);
322  if (! s) return NIL;
323  if (! s->wmes) return NIL;
324  return s->wmes->value;
325 }
326