1 /************************************************************************
2 **                                                                     **
3 **                   The YapTab/YapOr/OPTYap systems                   **
4 **                                                                     **
5 ** YapTab extends the Yap Prolog engine to support sequential tabling  **
6 ** YapOr extends the Yap Prolog engine to support or-parallelism       **
7 ** OPTYap extends the Yap Prolog engine to support or-parallel tabling **
8 **                                                                     **
9 **                                                                     **
10 **      Yap Prolog was developed at University of Porto, Portugal      **
11 **                                                                     **
12 ************************************************************************/
13 
14 /* -------------------- **
15 **      Prototypes      **
16 ** -------------------- */
17 
18 /* get a def for NULL */
19 #include <stdlib.h>
20 
21 STD_PROTO(static inline void PUT_IN_EXECUTING, (int));
22 STD_PROTO(static inline void PUT_OUT_EXECUTING, (int));
23 STD_PROTO(static inline void PUT_IN_FINISHED, (int));
24 #ifdef TABLING_INNER_CUTS
25 STD_PROTO(static inline void PUT_IN_PRUNING, (int));
26 STD_PROTO(static inline void PUT_OUT_PRUNING, (int));
27 #endif /* TABLING_INNER_CUTS */
28 
29 STD_PROTO(static inline void PUT_IN_REQUESTABLE, (int));
30 STD_PROTO(static inline void PUT_OUT_REQUESTABLE, (int));
31 STD_PROTO(static inline void SCH_update_local_or_tops, (void));
32 STD_PROTO(static inline void SCH_refuse_share_request_if_any, (void));
33 STD_PROTO(static inline void SCH_set_load, (choiceptr));
34 STD_PROTO(static inline void SCH_new_alternative, (yamop *,yamop *));
35 
36 STD_PROTO(static inline void CUT_send_prune_request, (int, choiceptr));
37 STD_PROTO(static inline void CUT_reset_prune_request, (void));
38 
39 STD_PROTO(static inline int CUT_last_worker_left_pending_prune, (or_fr_ptr));
40 STD_PROTO(static inline or_fr_ptr CUT_leftmost_or_frame, (void));
41 #ifdef TABLING_INNER_CUTS
42 STD_PROTO(static inline or_fr_ptr CUT_leftmost_until, (or_fr_ptr, int));
43 #endif /* TABLING_INNER_CUTS */
44 
45 STD_PROTO(static inline void CUT_store_answer, (or_fr_ptr, qg_ans_fr_ptr));
46 STD_PROTO(static inline void CUT_store_answers, (or_fr_ptr, qg_sol_fr_ptr));
47 STD_PROTO(static inline void CUT_join_answers_in_an_unique_frame, (qg_sol_fr_ptr));
48 STD_PROTO(static inline void CUT_free_solution_frame, (qg_sol_fr_ptr));
49 STD_PROTO(static inline void CUT_free_solution_frames, (qg_sol_fr_ptr));
50 STD_PROTO(static inline qg_sol_fr_ptr CUT_prune_solution_frames, (qg_sol_fr_ptr, int));
51 
52 
53 
54 /* ---------------------------- **
55 **      Instruction Macros      **
56 ** ---------------------------- */
57 
58 #if SIZEOF_INT == 2
59 #define YAMOP_CUT_FLAG    0x8000
60 #define YAMOP_SEQ_FLAG    0x4000
61 #define YAMOP_FLAGS_BITS  0xc000
62 #define YAMOP_LTT_BITS    0x3fff
63 #elif SIZEOF_INT == 4
64 #define YAMOP_CUT_FLAG    0x80000000
65 #define YAMOP_SEQ_FLAG    0x40000000
66 #define YAMOP_FLAGS_BITS  0xc0000000
67 #define YAMOP_LTT_BITS    0x3fffffff
68 #elif SIZEOF_INT == 8
69 #define YAMOP_CUT_FLAG    0x8000000000000000
70 #define YAMOP_SEQ_FLAG    0x4000000000000000
71 #define YAMOP_FLAGS_BITS  0xc000000000000000
72 #define YAMOP_LTT_BITS    0x3fffffffffffffff
73 #else
74 #define YAMOP_CUT_FLAG    OOOOPPS!!! Unknown Integer Sizeof
75 #define YAMOP_SEQ_FLAG    OOOOPPS!!! Unknown Integer Sizeof
76 #define YAMOP_FLAGS_BITS  OOOOPPS!!! Unknown Integer Sizeof
77 #define YAMOP_LTT_BITS    OOOOPPS!!! Unknown Integer Sizeof
78 #endif /* SIZEOF_INT */
79 
80 #define YAMOP_OR_ARG(INST)         ((INST)->u.Otapl.or_arg)
81 #define YAMOP_LTT(INST)            (((INST)->u.Otapl.or_arg) & YAMOP_LTT_BITS)
82 #define YAMOP_SEQ(INST)            (((INST)->u.Otapl.or_arg) & YAMOP_SEQ_FLAG)
83 #define YAMOP_CUT(INST)            (((INST)->u.Otapl.or_arg) & YAMOP_CUT_FLAG)
84 #define YAMOP_FLAGS(INST)          (((INST)->u.Otapl.or_arg) & YAMOP_FLAGS_BITS)
85 
86 #define INIT_YAMOP_LTT(INST, LTT)  ((INST)->u.Otapl.or_arg = LTT+1)
87 #define PUT_YAMOP_LTT(INST, LTT)   (INST)->u.Otapl.or_arg = YAMOP_FLAGS(INST) | (LTT+1)
88 #define PUT_YAMOP_SEQ(INST)        (INST)->u.Otapl.or_arg |= YAMOP_SEQ_FLAG
89 #define PUT_YAMOP_CUT(INST)        (INST)->u.Otapl.or_arg |= YAMOP_CUT_FLAG
90 
91 #define BRANCH(WORKER, DEPTH)      GLOBAL_branch(WORKER, DEPTH)
92 #define BRANCH_LTT(WORKER, DEPTH)  (BRANCH(WORKER, DEPTH) & YAMOP_LTT_BITS)
93 #define BRANCH_CUT(WORKER, DEPTH)  (BRANCH(WORKER, DEPTH) & YAMOP_CUT_FLAG)
94 
95 
96 
97 /* ---------------------------- **
98 **      Performance Macros      **
99 ** ---------------------------- */
100 
101 #define PERFORMANCE_OFF           0x0
102 #define PERFORMANCE_ON            0x1
103 #define PERFORMANCE_IN_EXECUTION  0x2
104 
105 
106 
107 /* ----------------------- **
108 **      Engine Macros      **
109 ** ----------------------- */
110 
111 #define LOCK_OR_FRAME(fr)      LOCK(OrFr_lock(fr))
112 #define UNLOCK_OR_FRAME(fr)  UNLOCK(OrFr_lock(fr))
113 
114 #define LOCK_WORKER(w)        LOCK(REMOTE_lock(w))
115 #define UNLOCK_WORKER(w)    UNLOCK(REMOTE_lock(w))
116 
117 
118 
119 /* -------------------------- **
120 **      Scheduler Macros      **
121 ** -------------------------- */
122 
123 #define SCH_top_shared_cp(CP)  (Get_LOCAL_top_cp() == CP)
124 
125 #define SCH_any_share_request  (LOCAL_share_request != MAX_WORKERS)
126 
127 #define SCHEDULER_GET_WORK()          \
128         if (get_work())               \
129           goto shared_fail;           \
130         else                          \
131           goto shared_end
132 
133 #define SCH_check_prune_request()     \
134   if (Get_LOCAL_prune_request()) {    \
135           SCHEDULER_GET_WORK();       \
136         }
137 
138 #if defined(ENV_COPY) || defined(SBA) || defined(THREADS)
139 #define SCH_check_share_request()     \
140         if (SCH_any_share_request) {  \
141 	  ASP = YENV;                 \
142 	  saveregs();                 \
143           p_share_work();             \
144 	  setregs();                  \
145         }
146 #else /* ACOW */
147 #define SCH_check_share_request()     \
148         if (SCH_any_share_request) {  \
149           if (! p_share_work())       \
150             goto shared_fail;         \
151         }
152 #endif /* ENV_COPY || SBA || ACOW */
153 
154 #define SCH_check_requests()          \
155         SCH_check_prune_request();    \
156         SCH_check_share_request()
157 
158 #define SCH_last_alternative(curpc, CP_PTR)    \
159         H = HBREG = PROTECT_FROZEN_H(CP_PTR);  \
160         CPREG = CP_PTR->cp_cp;		       \
161         ENV = CP_PTR->cp_env;                  \
162         SCH_new_alternative(curpc, NULL)
163 
164 
165 
166 /* -------------------- **
167 **      Cut Macros      **
168 ** -------------------- */
169 
170 #define CUT_prune_to(PRUNE_CP)                     \
171   if (YOUNGER_CP(Get_LOCAL_top_cp(), PRUNE_CP)) {  \
172     if (! Get_LOCAL_prune_request())		   \
173 	    prune_shared_branch(PRUNE_CP);         \
174 	  PRUNE_CP = Get_LOCAL_top_cp();	   \
175 	}
176 
177 #define CUT_wait_leftmost()                                           \
178         if (PARALLEL_EXECUTION_MODE) {                                \
179            /* parallel execution mode --> wait until leftmost */      \
180            int i, loop, depth, ltt;                                   \
181            bitmap members;                                            \
182            or_fr_ptr leftmost_or_fr;                                  \
183            leftmost_or_fr = LOCAL_top_or_fr;                          \
184            do {                                                       \
185              depth = OrFr_depth(leftmost_or_fr);                      \
186              ltt = BRANCH_LTT(worker_id, depth);                      \
187              do {                                                     \
188                loop = FALSE;                                          \
189                SCH_check_requests();                                  \
190                BITMAP_copy(members, OrFr_members(leftmost_or_fr));    \
191                BITMAP_delete(members, worker_id);                     \
192                for (i = 0; i < number_workers; i++) {                 \
193                  /*  not leftmost in current frame if there is a  */  \
194 	         /* worker in a left branch and it is not idle or */  \
195                  /*     if it is idle it is in a younger node     */  \
196                  if (BITMAP_member(members, i) &&                     \
197                      BRANCH_LTT(i, depth) > ltt &&                    \
198                      (! BITMAP_member(GLOBAL_bm_idle_workers, i) ||   \
199                       leftmost_or_fr != REMOTE_top_or_fr(i))) {       \
200                    loop = TRUE;                                       \
201                    break;                                             \
202                  }                                                    \
203                }                                                      \
204              } while (loop);                                          \
205              leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);  \
206            } while (leftmost_or_fr != GLOBAL_root_or_fr);             \
207          }
208 
209 
210 
211 /* ---------------------- **
212 **      Engine Stuff      **
213 ** ---------------------- */
214 
215 static inline
PUT_IN_EXECUTING(int w)216 void PUT_IN_EXECUTING(int w) {
217   LOCK(GLOBAL_LOCKS_bm_executing_workers);
218   BITMAP_insert(GLOBAL_bm_executing_workers, w);
219   UNLOCK(GLOBAL_LOCKS_bm_executing_workers);
220   return;
221 }
222 
223 
224 static inline
PUT_OUT_EXECUTING(int w)225 void PUT_OUT_EXECUTING(int w) {
226   LOCK(GLOBAL_LOCKS_bm_executing_workers);
227   BITMAP_delete(GLOBAL_bm_executing_workers, w);
228   UNLOCK(GLOBAL_LOCKS_bm_executing_workers);
229   return;
230 }
231 
232 
233 static inline
PUT_IN_FINISHED(int w)234 void PUT_IN_FINISHED(int w) {
235   LOCK(GLOBAL_LOCKS_bm_finished_workers);
236   BITMAP_insert(GLOBAL_bm_finished_workers, w);
237   UNLOCK(GLOBAL_LOCKS_bm_finished_workers);
238   return;
239 }
240 
241 
242 #ifdef TABLING_INNER_CUTS
243 static inline
PUT_IN_PRUNING(int w)244 void PUT_IN_PRUNING(int w) {
245   LOCK(GLOBAL_LOCKS_bm_pruning_workers);
246   BITMAP_insert(GLOBAL_bm_pruning_workers, w);
247   UNLOCK(GLOBAL_LOCKS_bm_pruning_workers);
248   return;
249 }
250 
251 
252 static inline
PUT_OUT_PRUNING(int w)253 void PUT_OUT_PRUNING(int w) {
254   LOCK(GLOBAL_LOCKS_bm_pruning_workers);
255   BITMAP_delete(GLOBAL_bm_pruning_workers, w);
256   UNLOCK(GLOBAL_LOCKS_bm_pruning_workers);
257   return;
258 }
259 #endif /* TABLING_INNER_CUTS */
260 
261 
262 
263 /* ------------------------- **
264 **      Scheduler Stuff      **
265 ** ------------------------- */
266 
267 static inline
PUT_IN_REQUESTABLE(int p)268 void PUT_IN_REQUESTABLE(int p) {
269   LOCK(GLOBAL_LOCKS_bm_requestable_workers);
270   BITMAP_insert(GLOBAL_bm_requestable_workers, p);
271   UNLOCK(GLOBAL_LOCKS_bm_requestable_workers);
272   return;
273 }
274 
275 
276 static inline
PUT_OUT_REQUESTABLE(int p)277 void PUT_OUT_REQUESTABLE(int p) {
278   LOCK(GLOBAL_LOCKS_bm_requestable_workers);
279   BITMAP_delete(GLOBAL_bm_requestable_workers, p);
280   UNLOCK(GLOBAL_LOCKS_bm_requestable_workers);
281   return;
282 }
283 
284 
285 static inline
SCH_update_local_or_tops(void)286 void SCH_update_local_or_tops(void) {
287   Set_LOCAL_top_cp(Get_LOCAL_top_cp()->cp_b);
288   LOCAL_top_or_fr = Get_LOCAL_top_cp()->cp_or_fr;
289   return;
290 }
291 
292 
293 static inline
SCH_refuse_share_request_if_any(void)294 void SCH_refuse_share_request_if_any(void)  {
295   if (SCH_any_share_request) {
296     REMOTE_reply_signal(LOCAL_share_request) = no_sharing;
297     LOCAL_share_request = MAX_WORKERS;
298     PUT_OUT_REQUESTABLE(worker_id);
299   }
300   return;
301 }
302 
303 
304 static inline
SCH_set_load(choiceptr current_cp)305 void SCH_set_load(choiceptr current_cp) {
306   Int lub;  /* local untried branches */
307   choiceptr previous_cp = current_cp->cp_b;
308 
309 #define INIT_CP_LUB(CP, LUB)  CP->cp_or_fr = (struct or_frame *)(LUB)
310 #define CP_LUB(CP)            (Int)(CP->cp_or_fr)
311 
312   if (SCH_top_shared_cp(previous_cp))
313     lub = 0;
314   else if (YAMOP_SEQ(previous_cp->cp_ap))
315     lub = CP_LUB(previous_cp);
316   else
317     lub = CP_LUB(previous_cp) + YAMOP_LTT(previous_cp->cp_ap);
318   INIT_CP_LUB(current_cp, lub);
319 
320   if (YAMOP_SEQ(current_cp->cp_ap))
321     LOCAL_load = lub;
322   else
323     LOCAL_load = lub + YAMOP_LTT(current_cp->cp_ap);
324   return;
325 }
326 
327 static inline
SCH_new_alternative(yamop * curpc,yamop * new)328 void SCH_new_alternative(yamop *curpc, yamop *new) {
329   OrFr_alternative(LOCAL_top_or_fr) = new;
330   BRANCH(worker_id, OrFr_depth(LOCAL_top_or_fr)) = YAMOP_OR_ARG(curpc);
331   UNLOCK_OR_FRAME(LOCAL_top_or_fr);
332   return;
333 }
334 
335 
336 
337 /* ---------------------------- **
338 **      Cut Stuff: Pruning      **
339 ** ---------------------------- */
340 
341 static inline
CUT_send_prune_request(int worker,choiceptr prune_cp)342 void CUT_send_prune_request(int worker, choiceptr prune_cp) {
343   LOCK_WORKER(worker);
344   if (YOUNGER_CP(REMOTE_top_cp(worker), prune_cp) &&
345      (! Get_REMOTE_prune_request(worker) || YOUNGER_CP(Get_REMOTE_prune_request(worker), prune_cp)))
346     Set_REMOTE_prune_request(worker, prune_cp);
347   UNLOCK_WORKER(worker);
348   return;
349 }
350 
351 
352 static inline
CUT_reset_prune_request(void)353 void CUT_reset_prune_request(void) {
354   LOCK_WORKER(worker_id);
355   if (Get_LOCAL_prune_request() && EQUAL_OR_YOUNGER_CP(Get_LOCAL_prune_request(), Get_LOCAL_top_cp()))
356     Set_LOCAL_prune_request(NULL);
357   UNLOCK_WORKER(worker_id);
358   return;
359 }
360 
361 
362 
363 /* ----------------------------- **
364 **      Cut Stuff: Leftmost      **
365 ** ----------------------------- */
366 
367 static inline
CUT_last_worker_left_pending_prune(or_fr_ptr or_frame)368 int CUT_last_worker_left_pending_prune(or_fr_ptr or_frame) {
369   int i, depth, ltt;
370   bitmap members;
371 
372   depth = OrFr_depth(or_frame);
373   ltt = OrFr_pend_prune_ltt(or_frame);
374   members = OrFr_members(or_frame);
375   BITMAP_delete(members, worker_id);
376   for (i = 0; i < number_workers; i++) {
377     if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt)
378       return FALSE;
379   }
380   return TRUE;
381 }
382 
383 
384 static inline
CUT_leftmost_or_frame(void)385 or_fr_ptr CUT_leftmost_or_frame(void) {
386   int i, depth, ltt;
387   bitmap members;
388   or_fr_ptr leftmost_or_fr, or_fr, nearest_or_fr;
389 
390   BITMAP_clear(members);
391   BITMAP_insert(members, worker_id);
392   leftmost_or_fr = LOCAL_top_or_fr;
393   depth = OrFr_depth(leftmost_or_fr);
394   do {
395     ltt = BRANCH_LTT(worker_id, depth);
396     BITMAP_difference(members, OrFr_members(leftmost_or_fr), members);
397     if (members)
398       for (i = 0; i < number_workers; i++)
399         if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt)
400           goto update_nearest_leftnode_data;
401     BITMAP_copy(members, OrFr_members(leftmost_or_fr));
402     leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);
403     depth = OrFr_depth(leftmost_or_fr);
404   } while (depth);
405 
406 update_nearest_leftnode_data:
407   or_fr = LOCAL_top_or_fr;
408   nearest_or_fr = OrFr_nearest_leftnode(or_fr);
409   while (OrFr_depth(nearest_or_fr) > depth) {
410     LOCK_OR_FRAME(or_fr);
411     OrFr_nearest_leftnode(or_fr) = leftmost_or_fr;
412     UNLOCK_OR_FRAME(or_fr);
413     or_fr = nearest_or_fr;
414     nearest_or_fr = OrFr_nearest_leftnode(or_fr);
415   }
416 
417   return leftmost_or_fr;
418 }
419 
420 
421 #ifdef TABLING_INNER_CUTS
422 static inline
CUT_leftmost_until(or_fr_ptr start_or_fr,int until_depth)423 or_fr_ptr CUT_leftmost_until(or_fr_ptr start_or_fr, int until_depth) {
424   int i, ltt, depth;
425   bitmap prune_members, members;
426   or_fr_ptr leftmost_or_fr, nearest_or_fr;
427 
428   /* we assume that the start_or_fr frame is locked and empty (without members) */
429   leftmost_or_fr = OrFr_nearest_leftnode(start_or_fr);
430   depth = OrFr_depth(leftmost_or_fr);
431   if (depth > until_depth) {
432     BITMAP_copy(prune_members, GLOBAL_bm_pruning_workers);
433     BITMAP_delete(prune_members, worker_id);
434     ltt = BRANCH_LTT(worker_id, depth);
435     BITMAP_intersection(members, prune_members, OrFr_members(leftmost_or_fr));
436     if (members) {
437       for (i = 0; i < number_workers; i++) {
438         if (BITMAP_member(members, i) &&
439             BRANCH_LTT(i, depth) > ltt &&
440             EQUAL_OR_YOUNGER_CP(GetOrFr_node(leftmost_or_fr), REMOTE_pruning_scope(i)))
441           return leftmost_or_fr;
442       }
443       BITMAP_minus(prune_members, members);
444     }
445     /* reaching that point we should update the nearest leftnode data before return */
446     leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);
447     depth = OrFr_depth(leftmost_or_fr);
448     while (depth > until_depth) {
449       ltt = BRANCH_LTT(worker_id, depth);
450       BITMAP_intersection(members, prune_members, OrFr_members(leftmost_or_fr));
451       if (members) {
452         for (i = 0; i < number_workers; i++) {
453           if (BITMAP_member(members, i) &&
454               BRANCH_LTT(i, depth) > ltt &&
455               EQUAL_OR_YOUNGER_CP(GetOrFr_node(leftmost_or_fr), REMOTE_pruning_scope(i))) {
456             /* update nearest leftnode data */
457             OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
458             start_or_fr = OrFr_nearest_leftnode(start_or_fr);
459             nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
460             while (OrFr_depth(nearest_or_fr) > depth) {
461               LOCK_OR_FRAME(start_or_fr);
462               OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
463               UNLOCK_OR_FRAME(start_or_fr);
464               start_or_fr = nearest_or_fr;
465               nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
466             }
467             return leftmost_or_fr;
468 	  }
469         }
470         BITMAP_minus(prune_members, members);
471       }
472       leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr);
473       depth = OrFr_depth(leftmost_or_fr);
474     }
475     /* update nearest leftnode data */
476     OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
477     start_or_fr = OrFr_nearest_leftnode(start_or_fr);
478     nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
479     while (OrFr_depth(nearest_or_fr) > depth) {
480       LOCK_OR_FRAME(start_or_fr);
481       OrFr_nearest_leftnode(start_or_fr) = leftmost_or_fr;
482       UNLOCK_OR_FRAME(start_or_fr);
483       start_or_fr = nearest_or_fr;
484       nearest_or_fr = OrFr_nearest_leftnode(start_or_fr);
485     }
486   }
487   return NULL;
488 }
489 #endif /* TABLING_INNER_CUTS */
490 
491 
492 
493 /* ------------------------------------------------ **
494 **      Cut Stuff: Managing query goal answers      **
495 ** ------------------------------------------------ */
496 
497 static inline
CUT_store_answer(or_fr_ptr or_frame,qg_ans_fr_ptr new_answer)498 void CUT_store_answer(or_fr_ptr or_frame, qg_ans_fr_ptr new_answer) {
499   int ltt;
500   qg_sol_fr_ptr *solution_ptr;
501 
502   ltt = BRANCH_LTT(worker_id, OrFr_depth(or_frame));
503   solution_ptr = & OrFr_qg_solutions(or_frame);
504   while (*solution_ptr && ltt > SolFr_ltt(*solution_ptr)) {
505     solution_ptr = & SolFr_next(*solution_ptr);
506   }
507   if (*solution_ptr && ltt == SolFr_ltt(*solution_ptr)) {
508     AnsFr_next(SolFr_last(*solution_ptr)) = new_answer;
509     SolFr_last(*solution_ptr) = new_answer;
510   } else {
511     qg_sol_fr_ptr new_solution;
512     ALLOC_QG_SOLUTION_FRAME(new_solution);
513     SolFr_next(new_solution) = *solution_ptr;
514     SolFr_ltt(new_solution) = ltt;
515     SolFr_first(new_solution) = new_answer;
516     SolFr_last(new_solution) = new_answer;
517     *solution_ptr = new_solution;
518   }
519   return;
520 }
521 
522 
523 static inline
CUT_store_answers(or_fr_ptr or_frame,qg_sol_fr_ptr new_solution)524 void CUT_store_answers(or_fr_ptr or_frame, qg_sol_fr_ptr new_solution) {
525   int ltt;
526   qg_sol_fr_ptr *solution_ptr;
527 
528   ltt = BRANCH_LTT(worker_id, OrFr_depth(or_frame));
529   solution_ptr = & OrFr_qg_solutions(or_frame);
530   while (*solution_ptr && ltt > SolFr_ltt(*solution_ptr)) {
531     solution_ptr = & SolFr_next(*solution_ptr);
532   }
533   if (*solution_ptr && ltt == SolFr_ltt(*solution_ptr)) {
534     AnsFr_next(SolFr_last(*solution_ptr)) = SolFr_first(new_solution);
535     SolFr_last(*solution_ptr) = SolFr_last(new_solution);
536     FREE_QG_SOLUTION_FRAME(new_solution);
537   } else {
538     SolFr_next(new_solution) = *solution_ptr;
539     SolFr_ltt(new_solution) = ltt;
540     *solution_ptr = new_solution;
541   }
542   return;
543 }
544 
545 
546 static inline
CUT_join_answers_in_an_unique_frame(qg_sol_fr_ptr join_solution)547 void CUT_join_answers_in_an_unique_frame(qg_sol_fr_ptr join_solution) {
548   qg_sol_fr_ptr next_solution;
549 
550   while ((next_solution = SolFr_next(join_solution))) {
551     AnsFr_next(SolFr_last(join_solution)) = SolFr_first(next_solution);
552     SolFr_last(join_solution) = SolFr_last(next_solution);
553     SolFr_next(join_solution) = SolFr_next(next_solution);
554     FREE_QG_SOLUTION_FRAME(next_solution);
555   }
556   return;
557 }
558 
559 
560 static inline
CUT_free_solution_frame(qg_sol_fr_ptr solution)561 void CUT_free_solution_frame(qg_sol_fr_ptr solution) {
562   qg_ans_fr_ptr current_answer, next_answer;
563 
564   current_answer = SolFr_first(solution);
565   do {
566     next_answer = AnsFr_next(current_answer);
567     FREE_QG_ANSWER_FRAME(current_answer);
568     current_answer = next_answer;
569   } while (current_answer);
570   FREE_QG_SOLUTION_FRAME(solution);
571   return;
572 }
573 
574 
575 static inline
CUT_free_solution_frames(qg_sol_fr_ptr current_solution)576 void CUT_free_solution_frames(qg_sol_fr_ptr current_solution) {
577   qg_sol_fr_ptr next_solution;
578 
579   while (current_solution) {
580     next_solution = SolFr_next(current_solution);
581     CUT_free_solution_frame(current_solution);
582     current_solution = next_solution;
583   }
584   return;
585 }
586 
587 
588 static inline
CUT_prune_solution_frames(qg_sol_fr_ptr solutions,int ltt)589 qg_sol_fr_ptr CUT_prune_solution_frames(qg_sol_fr_ptr solutions, int ltt) {
590   qg_sol_fr_ptr next_solution;
591 
592   while (solutions && ltt > SolFr_ltt(solutions)) {
593     next_solution = SolFr_next(solutions);
594     CUT_free_solution_frame(solutions);
595     solutions = next_solution;
596   }
597   return solutions;
598 }
599