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 **                          Memory management                          **
16 ************************************************************************/
17 
18 extern int Yap_page_size;
19 
20 #ifdef SHM_MEMORY_ALLOC_SCHEME
21 #include <sys/shm.h>
22 #define SHMMAX 0x2000000  /* 32 Mbytes: works fine with linux */
23 /* #define SHMMAX  0x400000 - 4 Mbytes: shmget limit for Mac (?) */
24 /* #define SHMMAX  0x800000 - 8 Mbytes: shmget limit for Solaris (?) */
25 #endif /* SHM_MEMORY_ALLOC_SCHEME */
26 
27 #if SIZEOF_INT_P == 4
28 #define ALIGN	                   3
29 #define ALIGNMASK                  0xfffffffc
30 #elif SIZEOF_INT_P == 8
31 #define ALIGN	                   7
32 #define ALIGNMASK                  0xfffffff8
33 #else
34 #define ALIGN	                   OOOOPPS!!! Unknown Pointer Sizeof
35 #define ALIGNMASK                  OOOOPPS!!! Unknown Pointer Sizeof
36 #endif /* SIZEOF_INT_P */
37 
38 #define ADJUST_SIZE(SIZE)          ((SIZE + ALIGN) & ALIGNMASK)
39 #define ADJUST_SIZE_TO_PAGE(SIZE)  ((SIZE) - (SIZE) % Yap_page_size + Yap_page_size)
40 #define STRUCT_SIZE(STR_TYPE)      ADJUST_SIZE(sizeof(STR_TYPE))
41 #define PAGE_HEADER(STR)           (pg_hd_ptr)((unsigned long int)STR - (unsigned long int)STR % Yap_page_size)
42 #define STRUCT_NEXT(STR)           ((STR)->next)
43 
44 #define UPDATE_STATS(STAT, VALUE)  STAT += VALUE
45 
46 
47 #ifdef MALLOC_MEMORY_ALLOC_SCHEME
48 /*************************************************************************************************
49 **                                  MALLOC_MEMORY_ALLOC_SCHEME                                  **
50 *************************************************************************************************/
51 #define ALLOC_BLOCK(STR, SIZE, STR_TYPE)                                                         \
52         if ((STR = (STR_TYPE *) malloc(SIZE)) == NULL)                                           \
53           Yap_Error(FATAL_ERROR, TermNil, "ALLOC_BLOCK: malloc error")
54 #define FREE_BLOCK(STR)                                                                          \
55         free(STR)
56 #else
57 /*************************************************************************************************
58 **                                 ! MALLOC_MEMORY_ALLOC_SCHEME                                 **
59 *************************************************************************************************/
60 #define ALLOC_BLOCK(STR, SIZE, STR_TYPE)                                                         \
61         { char *block_ptr;                                                                       \
62           if ((block_ptr = Yap_AllocCodeSpace(SIZE + sizeof(CELL))) != NULL)                     \
63             *block_ptr = 'y';                                                                    \
64           else if ((block_ptr = (char *) malloc(SIZE + sizeof(CELL))) != NULL)                   \
65             *block_ptr = 'm';                                                                    \
66           else                                                                                   \
67             Yap_Error(FATAL_ERROR, TermNil, "ALLOC_BLOCK: malloc error");                        \
68           block_ptr += sizeof(CELL);                                                             \
69           STR = (STR_TYPE *) block_ptr;                                                          \
70         }
71 #define FREE_BLOCK(STR)                                                                          \
72         { char *block_ptr = (char *)(STR) - sizeof(CELL);                                        \
73           if (block_ptr[0] == 'y')                                                               \
74             Yap_FreeCodeSpace(block_ptr);                                                        \
75           else                                                                                   \
76             free(block_ptr);                                                                     \
77         }
78 #endif /*****************************************************************************************/
79 
80 
81 #if defined(MALLOC_MEMORY_ALLOC_SCHEME) || defined(YAP_MEMORY_ALLOC_SCHEME)
82 /*************************************************************************************************
83 **                    MALLOC_MEMORY_ALLOC_SCHEME || YAP_MEMORY_ALLOC_SCHEME                     **
84 *************************************************************************************************/
85 #define ALLOC_STRUCT(STR, STR_PAGES, STR_TYPE)                                                   \
86         UPDATE_STATS(Pg_str_in_use(STR_PAGES), 1);                                               \
87         ALLOC_BLOCK(STR, sizeof(STR_TYPE), STR_TYPE)
88 #define ALLOC_NEXT_FREE_STRUCT(STR, STR_PAGES, STR_TYPE)                                         \
89         ALLOC_STRUCT(STR, STR_PAGES, STR_TYPE)
90 #define FREE_STRUCT(STR, STR_PAGES, STR_TYPE)                                                    \
91         UPDATE_STATS(Pg_str_in_use(STR_PAGES), -1);                                              \
92         FREE_BLOCK(STR)
93 #elif SHM_MEMORY_ALLOC_SCHEME
94 #ifdef LIMIT_TABLING
95 /*************************************************************************************************
96 **                          SHM_MEMORY_ALLOC_SCHEME && LIMIT_TABLING                            **
97 *************************************************************************************************/
98 #define INIT_PAGE(PG_HD, STR_PAGES, STR_TYPE)                                                    \
99         { int i;                                                                                 \
100           STR_TYPE *aux_str;                                                                     \
101           PgHd_str_in_use(PG_HD) = 0;                                                            \
102           PgHd_previous(PG_HD) = NULL;                                                           \
103           aux_str = (STR_TYPE *) (PG_HD + 1);                                                    \
104           PgHd_free_str(PG_HD) = (void *) aux_str;                                               \
105           for (i = 1; i < Pg_str_per_pg(STR_PAGES); i++) {                                       \
106             STRUCT_NEXT(aux_str) = aux_str + 1;                                                  \
107             aux_str++;                                                                           \
108           }                                                                                      \
109           STRUCT_NEXT(aux_str) = NULL;                                                           \
110           LOCK(Pg_lock(STR_PAGES));                                                              \
111           if ((PgHd_next(PG_HD) = Pg_free_pg(STR_PAGES)) != NULL)                                \
112             PgHd_previous(PgHd_next(PG_HD)) = PG_HD;                                             \
113           Pg_free_pg(STR_PAGES) = PG_HD;                                                         \
114           UPDATE_STATS(Pg_pg_alloc(STR_PAGES), 1);                                               \
115         }
116 
117 #define ALLOC_PAGE(PG_HD)                                                                        \
118         { int i, shmid;                                                                          \
119           pg_hd_ptr aux_pg_hd;                                                                   \
120           if ((shmid = shmget(IPC_PRIVATE, SHMMAX, SHM_R|SHM_W)) == -1)                          \
121             Yap_Error(FATAL_ERROR, TermNil, "shmget error (ALLOC_PAGE)");                        \
122           if ((PG_HD = (pg_hd_ptr) shmat(shmid, NULL, 0)) == (void *) -1)                        \
123             Yap_Error(FATAL_ERROR, TermNil, "shmat error (ALLOC_PAGE)");                         \
124           if (shmctl(shmid, IPC_RMID, 0) != 0)                                                   \
125             Yap_Error(FATAL_ERROR, TermNil, "shmctl error (ALLOC_PAGE)");                        \
126           aux_pg_hd = (pg_hd_ptr)(((void *)PG_HD) + Yap_page_size);                              \
127           Pg_free_pg(GLOBAL_PAGES_void) = aux_pg_hd;                                             \
128           for (i = 2; i < SHMMAX / Yap_page_size; i++) {                                         \
129             PgHd_next(aux_pg_hd) = (pg_hd_ptr)(((void *)aux_pg_hd) + Yap_page_size);             \
130             aux_pg_hd = PgHd_next(aux_pg_hd);                                                    \
131           }                                                                                      \
132           PgHd_next(aux_pg_hd) = NULL;                                                           \
133           UPDATE_STATS(Pg_pg_alloc(GLOBAL_PAGES_void), SHMMAX / Yap_page_size);                  \
134         }
135 
136 #define RECOVER_UNUSED_SPACE(STR_PAGES)                                                          \
137         { sg_fr_ptr sg_fr = GLOBAL_check_sg_fr;                                                  \
138           do {                                                                                   \
139             if (sg_fr)                                                                           \
140               sg_fr = SgFr_next(sg_fr);                                                          \
141             else                                                                                 \
142               sg_fr = GLOBAL_first_sg_fr;                                                        \
143             if (sg_fr == NULL)                                                                   \
144               Yap_Error(FATAL_ERROR, TermNil, "no space left (RECOVER_UNUSED_SPACE)");           \
145               /* see function 'InteractSIGINT' in file 'sysbits.c' */                            \
146               /* Yap_Error(PURE_ABORT, TermNil, "");               */                            \
147               /* restore_absmi_regs(&Yap_standard_regs);           */                            \
148               /* siglongjmp (Yap_RestartEnv, 1);                   */                            \
149             if (SgFr_first_answer(sg_fr) &&                                                      \
150                 SgFr_first_answer(sg_fr) != SgFr_answer_trie(sg_fr)) {                           \
151               SgFr_state(sg_fr) = ready;                                                         \
152 	      free_answer_hash_chain(SgFr_hash_chain(sg_fr));                                    \
153 	      SgFr_hash_chain(sg_fr) = NULL;                                                     \
154 	      SgFr_first_answer(sg_fr) = NULL;                                                   \
155               SgFr_last_answer(sg_fr) = NULL;                                                    \
156               free_answer_trie(TrNode_child(SgFr_answer_trie(sg_fr)),                            \
157                                TRAVERSE_MODE_NORMAL, TRAVERSE_POSITION_FIRST);                   \
158               TrNode_child(SgFr_answer_trie(sg_fr)) = NULL;                                      \
159 	    }                                                                                    \
160           } while (Pg_free_pg(GLOBAL_PAGES_void) == Pg_free_pg(STR_PAGES));                      \
161           GLOBAL_check_sg_fr = sg_fr;                                                            \
162         }
163 
164 #define ALLOC_STRUCT(STR, STR_PAGES, STR_TYPE)                                                   \
165         { pg_hd_ptr pg_hd;                                                                       \
166           LOCK(Pg_lock(STR_PAGES));                                                              \
167           pg_hd = Pg_free_pg(STR_PAGES);                                                         \
168           while (pg_hd == NULL) {                                                                \
169             UNLOCK(Pg_lock(STR_PAGES));                                                          \
170             LOCK(Pg_lock(GLOBAL_PAGES_void));                                                    \
171             if (Pg_free_pg(GLOBAL_PAGES_void)) {                                                 \
172               pg_hd = Pg_free_pg(GLOBAL_PAGES_void);                                             \
173               Pg_free_pg(GLOBAL_PAGES_void) = PgHd_next(pg_hd);                                  \
174               UPDATE_STATS(Pg_str_in_use(GLOBAL_PAGES_void), 1);                                 \
175               UNLOCK(Pg_lock(GLOBAL_PAGES_void));                                                \
176               INIT_PAGE(pg_hd, STR_PAGES, STR_TYPE);                                             \
177             } else if (GLOBAL_MAX_PAGES != Pg_pg_alloc(GLOBAL_PAGES_void)) {                     \
178               ALLOC_PAGE(pg_hd);                                                                 \
179               UPDATE_STATS(Pg_str_in_use(GLOBAL_PAGES_void), 1);                                 \
180               UNLOCK(Pg_lock(GLOBAL_PAGES_void));                                                \
181               INIT_PAGE(pg_hd, STR_PAGES, STR_TYPE);                                             \
182             } else {                                                                             \
183               UNLOCK(Pg_lock(GLOBAL_PAGES_void));                                                \
184               RECOVER_UNUSED_SPACE(STR_PAGES);                                                   \
185               LOCK(Pg_lock(STR_PAGES));                                                          \
186               pg_hd = Pg_free_pg(STR_PAGES);                                                     \
187             }                                                                                    \
188           }                                                                                      \
189           PgHd_str_in_use(pg_hd)++;                                                              \
190           STR = (STR_TYPE *) PgHd_free_str(pg_hd);                                               \
191           if ((PgHd_free_str(pg_hd) = (void *) STRUCT_NEXT(STR)) == NULL)                        \
192             if ((Pg_free_pg(STR_PAGES) = PgHd_next(pg_hd)) != NULL)                              \
193               PgHd_previous(PgHd_next(pg_hd)) = NULL;                                            \
194           UPDATE_STATS(Pg_str_in_use(STR_PAGES), 1);                                             \
195           UNLOCK(Pg_lock(STR_PAGES));                                                            \
196 	}
197 
198 #define ALLOC_NEXT_FREE_STRUCT(STR, STR_PAGES, STR_TYPE)                                         \
199         if ((STR = LOCAL_next_free_ans_node) == NULL) {                                          \
200           pg_hd_ptr pg_hd;                                                                       \
201           LOCK(Pg_lock(STR_PAGES));                                                              \
202           pg_hd = Pg_free_pg(STR_PAGES);                                                         \
203           while (pg_hd == NULL) {                                                                \
204             UNLOCK(Pg_lock(STR_PAGES));                                                          \
205             LOCK(Pg_lock(GLOBAL_PAGES_void));                                                    \
206             if (Pg_free_pg(GLOBAL_PAGES_void)) {                                                 \
207               pg_hd = Pg_free_pg(GLOBAL_PAGES_void);                                             \
208               Pg_free_pg(GLOBAL_PAGES_void) = PgHd_next(pg_hd);                                  \
209               UPDATE_STATS(Pg_str_in_use(GLOBAL_PAGES_void), 1);                                 \
210               UNLOCK(Pg_lock(GLOBAL_PAGES_void));                                                \
211               INIT_PAGE(pg_hd, STR_PAGES, STR_TYPE);                                             \
212             } else if (GLOBAL_MAX_PAGES != Pg_pg_alloc(GLOBAL_PAGES_void)) {                     \
213               ALLOC_PAGE(pg_hd);                                                                 \
214               UPDATE_STATS(Pg_str_in_use(GLOBAL_PAGES_void), 1);                                 \
215               UNLOCK(Pg_lock(GLOBAL_PAGES_void));                                                \
216               INIT_PAGE(pg_hd, STR_PAGES, STR_TYPE);                                             \
217             } else {                                                                             \
218               UNLOCK(Pg_lock(GLOBAL_PAGES_void));                                                \
219               RECOVER_UNUSED_SPACE(STR_PAGES);                                                   \
220               LOCK(Pg_lock(STR_PAGES));                                                          \
221               pg_hd = Pg_free_pg(STR_PAGES);                                                     \
222             }                                                                                    \
223           }                                                                                      \
224           PgHd_str_in_use(pg_hd) = Pg_str_per_pg(STR_PAGES);                                     \
225           STR = (STR_TYPE *) PgHd_free_str(pg_hd);                                               \
226           PgHd_free_str(pg_hd) = NULL;                                                           \
227           Pg_free_pg(STR_PAGES) = PgHd_next(pg_hd);                                              \
228           UPDATE_STATS(Pg_str_in_use(STR_PAGES), -PgHd_str_in_use(pg_hd));                       \
229           UPDATE_STATS(Pg_str_in_use(STR_PAGES), Pg_str_per_pg(STR_PAGES));                      \
230           UNLOCK(Pg_lock(STR_PAGES));                                                            \
231 	}                                                                                        \
232         LOCAL_next_free_ans_node = STRUCT_NEXT(STR)
233 #else
234 /*************************************************************************************************
235 **                          SHM_MEMORY_ALLOC_SCHEME && !LIMIT_TABLING                           **
236 *************************************************************************************************/
237 #define ALLOC_PAGE(PG_HD)                                                                        \
238         LOCK(Pg_lock(GLOBAL_PAGES_void));                                                        \
239         if (Pg_free_pg(GLOBAL_PAGES_void) == NULL) {                                             \
240           int i, shmid;                                                                          \
241           pg_hd_ptr pg_hd, aux_pg_hd;                                                            \
242           if ((shmid = shmget(IPC_PRIVATE, SHMMAX, SHM_R|SHM_W)) == -1)                          \
243             Yap_Error(FATAL_ERROR, TermNil, "shmget error (ALLOC_PAGE)");                        \
244           if ((pg_hd = (pg_hd_ptr) shmat(shmid, NULL, 0)) == (void *) -1)                        \
245             Yap_Error(FATAL_ERROR, TermNil, "shmat error (ALLOC_PAGE)");                         \
246           if (shmctl(shmid, IPC_RMID, 0) != 0)                                                   \
247             Yap_Error(FATAL_ERROR, TermNil, "shmctl error (ALLOC_PAGE)");                        \
248           Pg_free_pg(GLOBAL_PAGES_void) = pg_hd;                                                 \
249           for (i = 1; i < SHMMAX / Yap_page_size; i++) {                                         \
250             aux_pg_hd = (pg_hd_ptr)(((void *)pg_hd) + Yap_page_size);                            \
251             PgHd_next(pg_hd) = aux_pg_hd;                                                        \
252             pg_hd = aux_pg_hd;                                                                   \
253           }                                                                                      \
254           PgHd_next(pg_hd) = NULL;                                                               \
255           UPDATE_STATS(Pg_pg_alloc(GLOBAL_PAGES_void), SHMMAX / Yap_page_size);                  \
256         }                                                                                        \
257         UPDATE_STATS(Pg_str_in_use(GLOBAL_PAGES_void), 1);                                       \
258         PG_HD = Pg_free_pg(GLOBAL_PAGES_void);                                                   \
259         Pg_free_pg(GLOBAL_PAGES_void) = PgHd_next(PG_HD);                                        \
260         UNLOCK(Pg_lock(GLOBAL_PAGES_void))
261 
262 #define ALLOC_STRUCT(STR, STR_PAGES, STR_TYPE)                                                   \
263         { pg_hd_ptr pg_hd;                                                                       \
264           LOCK(Pg_lock(STR_PAGES));                                                              \
265           UPDATE_STATS(Pg_str_in_use(STR_PAGES), 1);                                             \
266           if (Pg_free_pg(STR_PAGES)) {                                                           \
267             pg_hd = Pg_free_pg(STR_PAGES);                                                       \
268             PgHd_str_in_use(pg_hd)++;                                                            \
269             STR = (STR_TYPE *) PgHd_free_str(pg_hd);                                             \
270             if ((PgHd_free_str(pg_hd) = (void *) STRUCT_NEXT(STR)) == NULL)                      \
271               if ((Pg_free_pg(STR_PAGES) = PgHd_next(pg_hd)) != NULL)                            \
272                 PgHd_previous(PgHd_next(pg_hd)) = NULL;                                          \
273             UNLOCK(Pg_lock(STR_PAGES));                                                          \
274           } else {                                                                               \
275             int i;                                                                               \
276             UPDATE_STATS(Pg_pg_alloc(STR_PAGES), 1);                                             \
277             UNLOCK(Pg_lock(STR_PAGES));                                                          \
278             ALLOC_PAGE(pg_hd);                                                                   \
279             PgHd_str_in_use(pg_hd) = 1;                                                          \
280             PgHd_previous(pg_hd) = NULL;                                                         \
281             STR = (STR_TYPE *) (pg_hd + 1);                                                      \
282             PgHd_free_str(pg_hd) = (void *) ++STR;                                               \
283             for (i = Pg_str_per_pg(STR_PAGES); i != 2; i--) {                                    \
284               STRUCT_NEXT(STR) = STR + 1;                                                        \
285               STR++;                                                                             \
286             }                                                                                    \
287             STRUCT_NEXT(STR) = NULL;                                                             \
288             STR = (STR_TYPE *) (pg_hd + 1);                                                      \
289             LOCK(Pg_lock(STR_PAGES));                                                            \
290             if ((PgHd_next(pg_hd) = Pg_free_pg(STR_PAGES)) != NULL)                              \
291               PgHd_previous(PgHd_next(pg_hd)) = pg_hd;                                           \
292             Pg_free_pg(STR_PAGES) = pg_hd;                                                       \
293             UNLOCK(Pg_lock(STR_PAGES));                                                          \
294           }                                                                                      \
295 	}
296 
297 #define ALLOC_NEXT_FREE_STRUCT(STR, STR_PAGES, STR_TYPE)                                         \
298         if ((STR = LOCAL_next_free_ans_node) == NULL) {                                          \
299           pg_hd_ptr pg_hd;                                                                       \
300           LOCK(Pg_lock(STR_PAGES));                                                              \
301           UPDATE_STATS(Pg_str_in_use(STR_PAGES), Pg_str_per_pg(STR_PAGES));                      \
302           if (Pg_free_pg(STR_PAGES)) {                                                           \
303             pg_hd = Pg_free_pg(STR_PAGES);                                                       \
304             UPDATE_STATS(Pg_str_in_use(STR_PAGES), -PgHd_str_in_use(pg_hd));                     \
305             PgHd_str_in_use(pg_hd) = Pg_str_per_pg(STR_PAGES);                                   \
306             STR = (STR_TYPE *) PgHd_free_str(pg_hd);                                             \
307             PgHd_free_str(pg_hd) = NULL;                                                         \
308             Pg_free_pg(STR_PAGES) = PgHd_next(pg_hd);                                            \
309             UNLOCK(Pg_lock(STR_PAGES));                                                          \
310           } else {                                                                               \
311             int i;                                                                               \
312             UPDATE_STATS(Pg_pg_alloc(STR_PAGES), 1);                                             \
313             UNLOCK(Pg_lock(STR_PAGES));                                                          \
314             ALLOC_PAGE(pg_hd);                                                                   \
315             PgHd_str_in_use(pg_hd) = Pg_str_per_pg(STR_PAGES);                                   \
316             PgHd_free_str(pg_hd) = NULL;                                                         \
317             PgHd_previous(pg_hd) = NULL;                                                         \
318             PgHd_next(pg_hd) = NULL;                                                             \
319             STR = (STR_TYPE *) (pg_hd + 1);                                                      \
320             for (i = Pg_str_per_pg(STR_PAGES); i != 1; i--) {                                    \
321               STRUCT_NEXT(STR) = STR + 1;                                                        \
322               STR++;                                                                             \
323             }                                                                                    \
324             STRUCT_NEXT(STR) = NULL;                                                             \
325             STR = (STR_TYPE *) (pg_hd + 1);                                                      \
326           }                                                                                      \
327 	}                                                                                        \
328         LOCAL_next_free_ans_node = STRUCT_NEXT(STR)
329 #endif /* LIMIT_TABLING */
330 /*************************************************************************************************
331 **                                   SHM_MEMORY_ALLOC_SCHEME                                    **
332 *************************************************************************************************/
333 #define FREE_PAGE(PG_HD)                                                                         \
334         LOCK(Pg_lock(GLOBAL_PAGES_void));                                                        \
335         UPDATE_STATS(Pg_str_in_use(GLOBAL_PAGES_void), -1);                                      \
336         PgHd_next(PG_HD) = Pg_free_pg(GLOBAL_PAGES_void);                                        \
337         Pg_free_pg(GLOBAL_PAGES_void) = PG_HD;                                                   \
338         UNLOCK(Pg_lock(GLOBAL_PAGES_void))
339 
340 #define FREE_STRUCT(STR, STR_PAGES, STR_TYPE)                                                    \
341         { pg_hd_ptr pg_hd;                                                                       \
342           pg_hd = PAGE_HEADER(STR);                                                              \
343           LOCK(Pg_lock(STR_PAGES));                                                              \
344           UPDATE_STATS(Pg_str_in_use(STR_PAGES), -1);                                            \
345           if (--PgHd_str_in_use(pg_hd) == 0) {                                                   \
346             UPDATE_STATS(Pg_pg_alloc(STR_PAGES), -1);                                            \
347             if (PgHd_previous(pg_hd)) {                                                          \
348               if ((PgHd_next(PgHd_previous(pg_hd)) = PgHd_next(pg_hd)) != NULL)                  \
349                 PgHd_previous(PgHd_next(pg_hd)) = PgHd_previous(pg_hd);                          \
350 	    } else {                                                                             \
351               if ((Pg_free_pg(STR_PAGES) = PgHd_next(pg_hd)) != NULL)                            \
352                 PgHd_previous(PgHd_next(pg_hd)) = NULL;                                          \
353 	    }                                                                                    \
354             UNLOCK(Pg_lock(STR_PAGES));                                                          \
355             FREE_PAGE(pg_hd);                                                                    \
356 	  } else {                                                                               \
357             if ((STRUCT_NEXT(STR) = (STR_TYPE *) PgHd_free_str(pg_hd)) == NULL) {                \
358               PgHd_previous(pg_hd) = NULL;                                                       \
359               if ((PgHd_next(pg_hd) = Pg_free_pg(STR_PAGES)) != NULL)                            \
360                 PgHd_previous(PgHd_next(pg_hd)) = pg_hd;                                         \
361               Pg_free_pg(STR_PAGES) = pg_hd;                                                     \
362             }                                                                                    \
363             PgHd_free_str(pg_hd) = (void *) STR;                                                 \
364             UNLOCK(Pg_lock(STR_PAGES));                                                          \
365           }                                                                                      \
366         }
367 #endif /*****************************************************************************************/
368 
369 #define ALLOC_HASH_BUCKETS(BUCKET_PTR, NUM_BUCKETS)                                              \
370         { int i; void **bucket_ptr;                                                              \
371           ALLOC_BLOCK(bucket_ptr, NUM_BUCKETS * sizeof(void *), void *);	                 \
372           BUCKET_PTR = (void *) bucket_ptr;                                                      \
373           for (i = NUM_BUCKETS; i != 0; i--)                                                     \
374             *bucket_ptr++ = NULL;                                                                \
375         }
376 #define FREE_HASH_BUCKETS(BUCKET_PTR)  FREE_BLOCK(BUCKET_PTR)
377 
378 #define ALLOC_OR_FRAME(STR)            ALLOC_STRUCT(STR, GLOBAL_PAGES_or_fr, struct or_frame)
379 #define FREE_OR_FRAME(STR)             FREE_STRUCT(STR, GLOBAL_PAGES_or_fr, struct or_frame)
380 
381 #define ALLOC_QG_SOLUTION_FRAME(STR)   ALLOC_STRUCT(STR, GLOBAL_PAGES_qg_sol_fr, struct query_goal_solution_frame)
382 #define FREE_QG_SOLUTION_FRAME(STR)    FREE_STRUCT(STR, GLOBAL_PAGES_qg_sol_fr, struct query_goal_solution_frame)
383 
384 #define ALLOC_QG_ANSWER_FRAME(STR)     ALLOC_STRUCT(STR, GLOBAL_PAGES_qg_ans_fr, struct query_goal_answer_frame)
385 #define FREE_QG_ANSWER_FRAME(STR)      FREE_STRUCT(STR, GLOBAL_PAGES_qg_ans_fr, struct query_goal_answer_frame)
386 
387 #define ALLOC_TG_SOLUTION_FRAME(STR)   ALLOC_STRUCT(STR, GLOBAL_PAGES_tg_sol_fr, struct table_subgoal_solution_frame)
388 #define FREE_TG_SOLUTION_FRAME(STR)    FREE_STRUCT(STR, GLOBAL_PAGES_tg_sol_fr, struct table_subgoal_solution_frame)
389 
390 #define ALLOC_TG_ANSWER_FRAME(STR)     ALLOC_STRUCT(STR, GLOBAL_PAGES_tg_ans_fr, struct table_subgoal_answer_frame)
391 #define FREE_TG_ANSWER_FRAME(STR)      FREE_STRUCT(STR, GLOBAL_PAGES_tg_ans_fr, struct table_subgoal_answer_frame)
392 
393 #define ALLOC_TABLE_ENTRY(STR)         ALLOC_STRUCT(STR, GLOBAL_PAGES_tab_ent, struct table_entry)
394 #define FREE_TABLE_ENTRY(STR)          FREE_STRUCT(STR, GLOBAL_PAGES_tab_ent, struct table_entry)
395 
396 #define ALLOC_SUBGOAL_FRAME(STR)       ALLOC_STRUCT(STR, GLOBAL_PAGES_sg_fr, struct subgoal_frame)
397 #define FREE_SUBGOAL_FRAME(STR)        FREE_STRUCT(STR, GLOBAL_PAGES_sg_fr, struct subgoal_frame)
398 
399 #define ALLOC_DEPENDENCY_FRAME(STR)    ALLOC_STRUCT(STR, GLOBAL_PAGES_dep_fr, struct dependency_frame)
400 #define FREE_DEPENDENCY_FRAME(STR)     FREE_STRUCT(STR, GLOBAL_PAGES_dep_fr, struct dependency_frame)
401 
402 #define ALLOC_SUSPENSION_FRAME(STR)    ALLOC_STRUCT(STR, GLOBAL_PAGES_susp_fr, struct suspension_frame)
403 #define FREE_SUSPENSION_FRAME(STR)     FREE_BLOCK(SuspFr_global_start(STR));                         \
404                                        FREE_STRUCT(STR, GLOBAL_PAGES_susp_fr, struct suspension_frame)
405 
406 #define ALLOC_GLOBAL_TRIE_NODE(STR)    ALLOC_STRUCT(STR, GLOBAL_PAGES_gt_node, struct global_trie_node)
407 #define FREE_GLOBAL_TRIE_NODE(STR)     FREE_STRUCT(STR, GLOBAL_PAGES_gt_node, struct global_trie_node)
408 
409 #define ALLOC_SUBGOAL_TRIE_NODE(STR)   ALLOC_STRUCT(STR, GLOBAL_PAGES_sg_node, struct subgoal_trie_node)
410 #define FREE_SUBGOAL_TRIE_NODE(STR)    FREE_STRUCT(STR, GLOBAL_PAGES_sg_node, struct subgoal_trie_node)
411 
412 #ifdef YAPOR
413 #define ALLOC_ANSWER_TRIE_NODE(STR)    ALLOC_NEXT_FREE_STRUCT(STR, GLOBAL_PAGES_ans_node, struct answer_trie_node)
414 #else /* TABLING */
415 #define ALLOC_ANSWER_TRIE_NODE(STR)    ALLOC_STRUCT(STR, GLOBAL_PAGES_ans_node, struct answer_trie_node)
416 #endif /* YAPOR - TABLING */
417 #define FREE_ANSWER_TRIE_NODE(STR)     FREE_STRUCT(STR, GLOBAL_PAGES_ans_node, struct answer_trie_node)
418 
419 #define ALLOC_GLOBAL_TRIE_HASH(STR)    ALLOC_STRUCT(STR, GLOBAL_PAGES_gt_hash, struct global_trie_hash)
420 #define FREE_GLOBAL_TRIE_HASH(STR)     FREE_STRUCT(STR, GLOBAL_PAGES_gt_hash, struct global_trie_hash)
421 
422 #define ALLOC_SUBGOAL_TRIE_HASH(STR)   ALLOC_STRUCT(STR, GLOBAL_PAGES_sg_hash, struct subgoal_trie_hash)
423 #define FREE_SUBGOAL_TRIE_HASH(STR)    FREE_STRUCT(STR, GLOBAL_PAGES_sg_hash, struct subgoal_trie_hash)
424 
425 #define ALLOC_ANSWER_TRIE_HASH(STR)    ALLOC_STRUCT(STR, GLOBAL_PAGES_ans_hash, struct answer_trie_hash)
426 #define FREE_ANSWER_TRIE_HASH(STR)     FREE_STRUCT(STR, GLOBAL_PAGES_ans_hash, struct answer_trie_hash)
427 
428 
429 
430 /************************************************************************
431 **                         Bitmap manipulation                         **
432 ************************************************************************/
433 
434 #define BITMAP_empty(b)		       ((b) == 0)
435 #define BITMAP_member(b,n)	       (((b) & (1<<(n))) != 0)
436 #define BITMAP_alone(b,n)	       ((b) == (1<<(n)))
437 #define BITMAP_subset(b1,b2)	       (((b1) & (b2)) == b2)
438 #define BITMAP_same(b1,b2)             ((b1) == (b2))
439 #define BITMAP_clear(b)	               ((b) = 0)
440 #define BITMAP_and(b1,b2)              ((b1) &= (b2))
441 #define BITMAP_minus(b1,b2)            ((b1) &= ~(b2))
442 #define BITMAP_insert(b,n)	       ((b) |= (1<<(n)))
443 #define BITMAP_delete(b,n)	       ((b) &= (~(1<<(n))))
444 #define BITMAP_copy(b1,b2)	       ((b1) = (b2))
445 #define BITMAP_intersection(b1,b2,b3)  ((b1) = ((b2) & (b3)))
446 #define BITMAP_difference(b1,b2,b3)    ((b1) = ((b2) & (~(b3))))
447 
448 
449 
450 /************************************************************************
451 **                            Debug macros                             **
452 ************************************************************************/
453 
454 #define INFORMATION_MESSAGE(MESSAGE,ARGS...)                            \
455         fprintf(stderr, "[ " MESSAGE " ]\n", ##ARGS)
456 
457 #ifdef YAPOR
458 #define ERROR_MESSAGE(MESSAGE)                                          \
459         Yap_Error(INTERNAL_ERROR, TermNil, "W%d - " MESSAGE, worker_id)
460 #else
461 #define ERROR_MESSAGE(MESSAGE)                                          \
462         Yap_Error(INTERNAL_ERROR, TermNil, MESSAGE)
463 #endif /* YAPOR */
464 
465 #ifdef DEBUG_TABLING
466 #define TABLING_ERROR_CHECKING(PROCEDURE,TEST)                          \
467         if (TEST) ERROR_MESSAGE(#PROCEDURE ": " #TEST)
468 #else
469 #define TABLING_ERROR_CHECKING(PROCEDURE,TEST)
470 #endif /* DEBUG_TABLING */
471 
472 #ifdef DEBUG_YAPOR
473 #define YAPOR_ERROR_CHECKING(PROCEDURE,TEST)                            \
474         if (TEST) ERROR_MESSAGE(#PROCEDURE ": " #TEST)
475 #else
476 #define YAPOR_ERROR_CHECKING(PROCEDURE,TEST)
477 #endif /* DEBUG_YAPOR */
478 
479 #ifdef DEBUG_OPTYAP
480 #define OPTYAP_ERROR_CHECKING(PROCEDURE,TEST)                           \
481         if (TEST) ERROR_MESSAGE(#PROCEDURE ": " #TEST)
482 #else
483 #define OPTYAP_ERROR_CHECKING(PROCEDURE,TEST)
484 #endif /* DEBUG_OPTYAP */
485