/************************************************************************* * * * YAP Prolog * * * * Yap Prolog was developed at NCCUP - Universidade do Porto * * * * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * * * ************************************************************************** * * * File: or.cowengine.c * * Last rev: * * mods: * * comments: * * * *************************************************************************/ /* ------------------ ** ** Includes ** ** ------------------ */ #include "Yap.h" #ifdef ACOW #include #include #include #include "Yatom.h" #include "YapHeap.h" #include "or.macros.h" /* ------------------------------------- ** ** Local functions declaration ** ** ------------------------------------- */ static void share_private_nodes(int worker_q); /* ----------------------- ** ** Local inlines ** ** ----------------------- */ STD_PROTO(static inline void PUT_BUSY, (int)); static inline void PUT_BUSY(int worker_num) { LOCK(GLOBAL_LOCKS_bm_idle_workers); BITMAP_delete(GLOBAL_bm_idle_workers, worker_num); UNLOCK(GLOBAL_LOCKS_bm_idle_workers); return; } /* -------------------------- ** ** Global functions ** ** -------------------------- */ void make_root_choice_point(void) { if (worker_id == 0) { LOCAL_top_cp = GLOBAL_root_cp = OrFr_node(GLOBAL_root_or_fr) = B; } else { B = LOCAL_top_cp = GLOBAL_root_cp; B->cp_tr = TR = ((choiceptr) (worker_offset(0) + (CELL)(B)))->cp_tr; } B->cp_h = H0; B->cp_ap = GETWORK; B->cp_or_fr = GLOBAL_root_or_fr; LOCAL_top_or_fr = GLOBAL_root_or_fr; LOCAL_load = 0; LOCAL_prune_request = NULL; BRANCH(worker_id, 0) = 0; return; } void free_root_choice_point(void) { B = LOCAL_top_cp->cp_b; LOCAL_top_cp = B_BASE; return; } int p_share_work(void) { int worker_q = LOCAL_share_request; int son; if (! BITMAP_member(OrFr_members(REMOTE_top_or_fr(worker_q)), worker_id) || B == REMOTE_top_cp(worker_q) || (LOCAL_load <= DELAYED_RELEASE_LOAD && OrFr_nearest_livenode(LOCAL_top_or_fr) == NULL)) { /* refuse sharing request */ REMOTE_reply_signal(LOCAL_share_request) = no_sharing; LOCAL_share_request = MAX_WORKERS; PUT_OUT_REQUESTABLE(worker_id); return TRUE; } /* sharing request accepted */ REMOTE_reply_signal(worker_q) = sharing; share_private_nodes(worker_q); if ((son = fork()) == 0) { worker_id = worker_q; /* child becomes requesting worker */ LOCAL = REMOTE + worker_id; LOCAL_reply_signal = ready; PUT_IN_REQUESTABLE(worker_id); PUT_BUSY(worker_id); return FALSE; } else { worker_pid(worker_q) = son; LOCAL_share_request = MAX_WORKERS; PUT_IN_REQUESTABLE(worker_id); return TRUE; } } int q_share_work(int worker_p) { LOCK_OR_FRAME(LOCAL_top_or_fr); if (REMOTE_prune_request(worker_p)) { /* worker p with prune request */ UNLOCK_OR_FRAME(LOCAL_top_or_fr); return FALSE; } #ifdef YAPOR_ERRORS if (OrFr_pend_prune_cp(LOCAL_top_or_fr) && BRANCH_LTT(worker_p, OrFr_depth(LOCAL_top_or_fr)) < OrFr_pend_prune_ltt(LOCAL_top_or_fr)) YAPOR_ERROR_MESSAGE("prune ltt > worker_p branch ltt (q_share_work)"); #endif /* YAPOR_ERRORS */ /* there is no pending prune with worker p at right --> safe move to worker p branch */ BRANCH(worker_id, OrFr_depth(LOCAL_top_or_fr)) = BRANCH(worker_p, OrFr_depth(LOCAL_top_or_fr)); LOCAL_prune_request = NULL; UNLOCK_OR_FRAME(LOCAL_top_or_fr); /* make sharing request */ LOCK_WORKER(worker_p); if (BITMAP_member(GLOBAL_bm_idle_workers, worker_p) || REMOTE_share_request(worker_p) != MAX_WORKERS) { /* worker p is idle or has another request */ UNLOCK_WORKER(worker_p); return FALSE; } REMOTE_share_request(worker_p) = worker_id; UNLOCK_WORKER(worker_p); /* wait for an answer */ while (LOCAL_reply_signal == ready); if (LOCAL_reply_signal == no_sharing) { /* sharing request refused */ LOCAL_reply_signal = ready; return FALSE; } /* exit this process */ exit(0); } /* ------------------------- ** ** Local functions ** ** ------------------------- */ static void share_private_nodes(int worker_q) { int depth; choiceptr AuxB; or_fr_ptr or_frame, previous_or_frame; /* initialize auxiliary variables */ AuxB = B; previous_or_frame = NULL; depth = OrFr_depth(LOCAL_top_or_fr); /* sharing loop */ while (AuxB != LOCAL_top_cp) { depth++; ALLOC_OR_FRAME(or_frame); INIT_LOCK(OrFr_lock(or_frame)); OrFr_node(or_frame) = AuxB; OrFr_alternative(or_frame) = AuxB->cp_ap; OrFr_pend_prune_cp(or_frame) = NULL; OrFr_nearest_leftnode(or_frame) = LOCAL_top_or_fr; OrFr_qg_solutions(or_frame) = NULL; BITMAP_clear(OrFr_members(or_frame)); BITMAP_insert(OrFr_members(or_frame), worker_id); BITMAP_insert(OrFr_members(or_frame), worker_q); if (AuxB->cp_ap && YAMOP_SEQ(AuxB->cp_ap)) { AuxB->cp_ap = GETWORK_SEQ; } else { AuxB->cp_ap = GETWORK; } AuxB->cp_or_fr = or_frame; AuxB = AuxB->cp_b; if (previous_or_frame) { OrFr_nearest_livenode(previous_or_frame) = OrFr_next(previous_or_frame) = or_frame; } previous_or_frame = or_frame; } /* initialize last or-frame pointer */ or_frame = AuxB->cp_or_fr; if (previous_or_frame) { OrFr_nearest_livenode(previous_or_frame) = OrFr_next(previous_or_frame) = or_frame; } /* update depth */ if (depth >= MAX_BRANCH_DEPTH) Yap_Error(INTERNAL_ERROR, TermNil, "maximum depth exceded (share_private_nodes)"); or_frame = B->cp_or_fr; while (or_frame != LOCAL_top_or_fr) { unsigned int branch; if (OrFr_alternative(or_frame)) { branch = YAMOP_OR_ARG(OrFr_alternative(or_frame)) + 1; } else { branch = 1; } branch |= YAMOP_CUT_FLAG; /* in doubt, assume cut */ BRANCH(worker_id, depth) = BRANCH(worker_q, depth) = branch; OrFr_depth(or_frame) = depth--; or_frame = OrFr_next_on_stack(or_frame); } /* update old shared nodes */ while (or_frame != REMOTE_top_or_fr(worker_q)) { LOCK_OR_FRAME(or_frame); BRANCH(worker_q, OrFr_depth(or_frame)) = BRANCH(worker_id, OrFr_depth(or_frame)); BITMAP_insert(OrFr_members(or_frame), worker_q); UNLOCK_OR_FRAME(or_frame); or_frame = OrFr_next_on_stack(or_frame); } /* update top shared nodes */ REMOTE_top_cp(worker_q) = LOCAL_top_cp = B; REMOTE_top_or_fr(worker_q) = LOCAL_top_or_fr = LOCAL_top_cp->cp_or_fr; /* update prune request */ if (LOCAL_prune_request) { CUT_send_prune_request(worker_q, LOCAL_prune_request); } /* update load and return */ REMOTE_load(worker_q) = LOCAL_load = 0; return; } #endif /* ACOW */