NodeStats subgoal_statistics(CTXTdeclc Structure_Manager *sm) { NodeStats sg_stats; TIFptr tif; int nSubgoals; VariantSF pProdSF; SubConsSF pConsSF; sg_stats = node_statistics(sm); nSubgoals = 0; SYS_MUTEX_LOCK( MUTEX_TABLE ); if ( sm == &smVarSF ) { for ( tif = tif_list.first; IsNonNULL(tif); tif = TIF_NextTIF(tif) ) if ( IsVariantPredicate(tif) ) for ( pProdSF = TIF_Subgoals(tif); IsNonNULL(pProdSF); pProdSF = (VariantSF)subg_next_subgoal(pProdSF) ) nSubgoals++; } /* No shared smProdSF or smConsSF in MT engine */ else if ( sm == &smProdSF ) { for ( tif = tif_list.first; IsNonNULL(tif); tif = TIF_NextTIF(tif) ) if ( IsSubsumptivePredicate(tif) ) for ( pProdSF = TIF_Subgoals(tif); IsNonNULL(pProdSF); pProdSF = (VariantSF)subg_next_subgoal(pProdSF) ) nSubgoals++; } else if ( sm == &smConsSF ) { for ( tif = tif_list.first; IsNonNULL(tif); tif = TIF_NextTIF(tif) ) if ( IsSubsumptivePredicate(tif) ) for ( pProdSF = TIF_Subgoals(tif); IsNonNULL(pProdSF); pProdSF = (VariantSF)subg_next_subgoal(pProdSF) ) for ( pConsSF = subg_consumers(pProdSF); IsNonNULL(pConsSF); pConsSF = conssf_consumers(pConsSF) ) nSubgoals++; } else { SYS_MUTEX_UNLOCK( MUTEX_TABLE ); xsb_dbgmsg((LOG_DEBUG, "Incorrect use of subgoal_statistics()\n" "SM does not contain subgoal frames")); return sg_stats; } SYS_MUTEX_UNLOCK( MUTEX_TABLE ); if ( NodeStats_NumUsedNodes(sg_stats) != (counter) nSubgoals ) xsb_warn(CTXTc "Inconsistent Subgoal Frame Usage Calculations:\n" "\tSubgoal Frame count mismatch"); return sg_stats; }
/* FD_SET the socket fds */ static void set_sockfd(CTXTdeclc int count) { int i; SYS_MUTEX_LOCK(MUTEX_SOCKETS); FD_ZERO(&connections[count].readset); FD_ZERO(&connections[count].writeset); FD_ZERO(&connections[count].exceptionset); for (i=0; i< connections[count].sizer; i++) { /* turn on the bit in the fd_set */ FD_SET(connections[count].read_fds[i], &connections[count].readset); } for (i=0; i< connections[count].sizew; i++) { /* turn on the bit in the fd_set */ FD_SET(connections[count].write_fds[i], &connections[count].writeset); } for (i=0; i< connections[count].sizee; i++) { /* turn on the bit in the fd_set */ FD_SET(connections[count].exception_fds[i], &connections[count].exceptionset); } SYS_MUTEX_UNLOCK(MUTEX_SOCKETS); }
/* initialize the array of the structure */ static void init_connections(CTXTdecl) { int i; static int initialized = FALSE; /* This is only initialized once. */ SYS_MUTEX_LOCK(MUTEX_SOCKETS); if (!initialized) { for (i=0; i<MAXCONNECT; i++) { connections[i].connection_name = NULL; connections[i].maximum_fd=0; connections[i].empty_flag=TRUE; /*clear all FD_SET */ FD_ZERO(&connections[i].readset); FD_ZERO(&connections[i].writeset); FD_ZERO(&connections[i].exceptionset); connections[i].read_fds = 0; connections[i].write_fds = 0 ; connections[i].exception_fds = 0; connections[i].sizer= 0; connections[i].sizew = 0 ; connections[i].sizee = 0 ; } initialized = TRUE; } SYS_MUTEX_UNLOCK(MUTEX_SOCKETS); }
void symbol_table_stats(CTXTdecl) { UInteger i, symbols, bucket_contains, used_buckets, unused_buckets, fullest_bucket_size, fullest_bucket_num, last_index; UInteger first_index; Pair pair_ptr; SYS_MUTEX_LOCK( MUTEX_SYMBOL ) ; symbols = used_buckets = unused_buckets = last_index = 0; fullest_bucket_size = fullest_bucket_num = 0; first_index = -1; for (i = 0; i < symbol_table.size; i++) { if (symbol_table.table[i] != NULL) { if (first_index == -1) first_index = i; last_index = i; used_buckets++; bucket_contains = 0; for (pair_ptr = (Pair)symbol_table.table[i]; pair_ptr != NULL; pair_ptr = pair_next(pair_ptr)) { symbols++; bucket_contains++; } if (bucket_contains > fullest_bucket_size) { fullest_bucket_size = bucket_contains; fullest_bucket_num = i; } } else unused_buckets++; } printf("\nSymbol table statistics:"); printf("\n------------------------\n"); printf("Table Size:\t%" UIntfmt "\n", symbol_table.size); printf("Total Symbols:\t%" UIntfmt "\n", symbols); if (symbols != symbol_table.contains) printf("Symbol count incorrect in 'symbol_table': %" UIntfmt "\n", symbol_table.contains); printf("\tused buckets:\t%" UIntfmt " (range: [%" Intfmt", %" UIntfmt "])\n", used_buckets, first_index, last_index); printf("\tunused buckets:\t%" UIntfmt "\n", unused_buckets); printf("\tmaximum bucket size:\t%" UIntfmt " (#: %" UIntfmt ")\n", fullest_bucket_size, fullest_bucket_num); SYS_MUTEX_UNLOCK( MUTEX_SYMBOL ) ; }
void string_table_stats(CTXTdecl) { UInteger i, strings, bucket_contains, used_buckets, unused_buckets, fullest_bucket_size, fullest_bucket_num, last_index; UInteger first_index; void *ptr; SYS_MUTEX_LOCK( MUTEX_STRING ) ; strings = used_buckets = unused_buckets = last_index = 0; fullest_bucket_size = fullest_bucket_num = 0; first_index = -1; for (i = 0; i < string_table.size; i++) { if (string_table.table[i] != NULL) { if (first_index == -1) first_index = i; last_index = i; used_buckets++; bucket_contains = 0; for (ptr = string_table.table[i]; ptr != NULL; ptr = *(void **)ptr) { strings++; bucket_contains++; } if (bucket_contains > fullest_bucket_size) { fullest_bucket_size = bucket_contains; fullest_bucket_num = i; } } else unused_buckets++; } printf("\nString table statistics:"); printf("\n------------------------\n"); printf("Table Size:\t%" UIntfmt "\n", string_table.size); printf("Total Strings:\t%" UIntfmt "\n", strings); if (strings != string_table.contains) printf("String count incorrect in 'string_table': %" UIntfmt "\n", string_table.contains); printf("\tused buckets:\t%" UIntfmt " (range: [%" Intfmt ", %" UIntfmt "])\n", used_buckets, first_index, last_index); printf("\tunused buckets:\t%" UIntfmt "\n", unused_buckets); printf("\tmaximum bucket size:\t%" UIntfmt " (#: %" UIntfmt ")\n", fullest_bucket_size, fullest_bucket_num); SYS_MUTEX_UNLOCK( MUTEX_STRING ) ; }
/* utility function to destroy a select call */ static void select_destroy(CTXTdeclc char *connection_name) { int i; int connectname_found = FALSE; SYS_MUTEX_LOCK(MUTEX_SOCKETS); for (i=0; i < MAXCONNECT; i++) { if(connections[i].empty_flag==FALSE) { /* find the matching connection_name to destroy */ if (strcmp(connection_name, connections[i].connection_name) == 0) { connectname_found = TRUE; /* destroy the corresponding structure */ FD_ZERO(&connections[i].readset); FD_ZERO(&connections[i].writeset); FD_ZERO(&connections[i].exceptionset); connections[i].connection_name = NULL; connections[i].maximum_fd = 0; /* free the fds obtained by mem_alloc() */ mem_dealloc(connections[i].read_fds,connections[i].sizer,OTHER_SPACE); mem_dealloc(connections[i].write_fds,connections[i].sizew,OTHER_SPACE); mem_dealloc(connections[i].exception_fds,connections[i].sizee,OTHER_SPACE); connections[i].sizer = 0; connections[i].sizew = 0 ; connections[i].sizee = 0 ; connections[i].empty_flag = TRUE; /* set the destroyed slot to empty */ break; } } } SYS_MUTEX_UNLOCK(MUTEX_SOCKETS); /* if no matching connection_name */ if (!connectname_found) xsb_abort("[SOCKET_SELECT_DESTROY] connection `%s' doesn't exist", connection_name); SQUASH_LINUX_COMPILER_WARN(connectname_found) ; }
/* TLS: making a conservative guess at which system calls need to be mutexed. I'm doing it whenever I see the process table altered or affected, so this is the data structure that its protecting. At some point, the SET_FILEPTRs should be protected against other threads closing that stream. Perhaps for such things a thread-specific stream table should be used. */ xsbBool sys_system(CTXTdeclc int callno) { // int pid; Integer pid; switch (callno) { case PLAIN_SYSTEM_CALL: /* dumb system call: no communication with XSB */ /* this call is superseded by shell and isn't used */ ctop_int(CTXTc 3, system(ptoc_string(CTXTc 2))); return TRUE; case SLEEP_FOR_SECS: #ifdef WIN_NT Sleep((int)iso_ptoc_int_arg(CTXTc 2,"sleep/1",1) * 1000); #else sleep(iso_ptoc_int_arg(CTXTc 2,"sleep/1",1)); #endif return TRUE; case GET_TMP_FILENAME: ctop_string(CTXTc 2,tempnam(NULL,NULL)); return TRUE; case IS_PLAIN_FILE: case IS_DIRECTORY: case STAT_FILE_TIME: case STAT_FILE_SIZE: return file_stat(CTXTc callno, ptoc_longstring(CTXTc 2)); case EXEC: { #ifdef HAVE_EXECVP /* execs a new process in place of XSB */ char *params[MAX_SUBPROC_PARAMS+2]; prolog_term cmdspec_term; int index = 0; cmdspec_term = reg_term(CTXTc 2); if (islist(cmdspec_term)) { prolog_term temp, head; char *string_head=NULL; if (isnil(cmdspec_term)) xsb_abort("[exec] Arg 1 must not be an empty list."); temp = cmdspec_term; do { head = p2p_car(temp); temp = p2p_cdr(temp); if (isstring(head)) string_head = string_val(head); else xsb_abort("[exec] non-string argument passed in list."); params[index++] = string_head; if (index > MAX_SUBPROC_PARAMS) xsb_abort("[exec] Too many arguments."); } while (!isnil(temp)); params[index] = NULL; } else if (isstring(cmdspec_term)) { char *string = string_val(cmdspec_term); split_command_arguments(string, params, "exec"); } else xsb_abort("[exec] 1st argument should be term or list of strings."); if (execvp(params[0], params)) xsb_abort("[exec] Exec call failed."); #else xsb_abort("[exec] builtin not supported in this architecture."); #endif } case SHELL: /* smart system call: like SPAWN_PROCESS, but returns error code instead of PID. Uses system() rather than execvp. Advantage: can pass arbitrary shell command. */ case SPAWN_PROCESS: { /* spawn new process, reroute stdin/out/err to XSB */ /* +CallNo=2, +ProcAndArgsList, -StreamToProc, -StreamFromProc, -StreamFromProcStderr, -Pid */ static int pipe_to_proc[2], pipe_from_proc[2], pipe_from_stderr[2]; int toproc_stream=-1, fromproc_stream=-1, fromproc_stderr_stream=-1; int pid_or_status; FILE *toprocess_fptr=NULL, *fromprocess_fptr=NULL, *fromproc_stderr_fptr=NULL; char *params[MAX_SUBPROC_PARAMS+2]; /* one for progname--0th member, one for NULL termination*/ prolog_term cmdspec_term, cmdlist_temp_term; prolog_term cmd_or_arg_term; xsbBool toproc_needed=FALSE, fromproc_needed=FALSE, fromstderr_needed=FALSE; char *cmd_or_arg=NULL, *shell_cmd=NULL; int idx = 0, tbl_pos; char *callname=NULL; xsbBool params_are_in_a_list=FALSE; SYS_MUTEX_LOCK( MUTEX_SYS_SYSTEM ); init_process_table(); if (callno == SPAWN_PROCESS) callname = "spawn_process/5"; else callname = "shell/[1,2,5]"; cmdspec_term = reg_term(CTXTc 2); if (islist(cmdspec_term)) params_are_in_a_list = TRUE; else if (isstring(cmdspec_term)) shell_cmd = string_val(cmdspec_term); else if (isref(cmdspec_term)) xsb_instantiation_error(CTXTc callname,1); else xsb_type_error(CTXTc "atom or list e.g. [command, arg, ...]",cmdspec_term,callname,1); // xsb_abort("[%s] Arg 1 must be an atom or a list [command, arg, ...]", // callname); /* the user can indicate that he doesn't want either of the streams created by putting an atom in the corresponding argument position */ if (isref(reg_term(CTXTc 3))) toproc_needed = TRUE; if (isref(reg_term(CTXTc 4))) fromproc_needed = TRUE; if (isref(reg_term(CTXTc 5))) fromstderr_needed = TRUE; /* if any of the arg streams is already used by XSB, then don't create pipes --- use these streams instead. */ if (isointeger(reg_term(CTXTc 3))) { SET_FILEPTR(toprocess_fptr, oint_val(reg_term(CTXTc 3))); } if (isointeger(reg_term(CTXTc 4))) { SET_FILEPTR(fromprocess_fptr, oint_val(reg_term(CTXTc 4))); } if (isointeger(reg_term(CTXTc 5))) { SET_FILEPTR(fromproc_stderr_fptr, oint_val(reg_term(CTXTc 5))); } if (!isref(reg_term(CTXTc 6))) xsb_type_error(CTXTc "variable (to return process id)",reg_term(CTXTc 6),callname,5); // xsb_abort("[%s] Arg 5 (process id) must be a variable", callname); if (params_are_in_a_list) { /* fill in the params[] array */ if (isnil(cmdspec_term)) xsb_abort("[%s] Arg 1 must not be an empty list", callname); cmdlist_temp_term = cmdspec_term; do { cmd_or_arg_term = p2p_car(cmdlist_temp_term); cmdlist_temp_term = p2p_cdr(cmdlist_temp_term); if (isstring(cmd_or_arg_term)) { cmd_or_arg = string_val(cmd_or_arg_term); } else xsb_abort("[%s] Non string list member in the Arg", callname); params[idx++] = cmd_or_arg; if (idx > MAX_SUBPROC_PARAMS) xsb_abort("[%s] Too many arguments passed to subprocess", callname); } while (!isnil(cmdlist_temp_term)); params[idx] = NULL; /* null termination */ } else { /* params are in a string */ if (callno == SPAWN_PROCESS) split_command_arguments(shell_cmd, params, callname); else { /* if callno==SHELL => call system() => don't split shell_cmd */ params[0] = shell_cmd; params[1] = NULL; } } /* -1 means: no space left */ if ((tbl_pos = get_free_process_cell()) < 0) { xsb_warn(CTXTc "Can't create subprocess because XSB process table is full"); SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return FALSE; } /* params[0] is the progname */ pid_or_status = xsb_spawn(CTXTc params[0], params, callno, (toproc_needed ? pipe_to_proc : NULL), (fromproc_needed ? pipe_from_proc : NULL), (fromstderr_needed ? pipe_from_stderr : NULL), toprocess_fptr, fromprocess_fptr, fromproc_stderr_fptr); if (pid_or_status < 0) { xsb_warn(CTXTc "[%s] Subprocess creation failed, Error: %d, errno: %d, Cmd: %s", callname,pid_or_status,errno,params[0]); SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return FALSE; } if (toproc_needed) { toprocess_fptr = fdopen(pipe_to_proc[1], "w"); toproc_stream = xsb_intern_fileptr(CTXTc toprocess_fptr,callname,"pipe","w",CURRENT_CHARSET); ctop_int(CTXTc 3, toproc_stream); } if (fromproc_needed) { fromprocess_fptr = fdopen(pipe_from_proc[0], "r"); fromproc_stream = xsb_intern_fileptr(CTXTc fromprocess_fptr,callname,"pipe","r",CURRENT_CHARSET); ctop_int(CTXTc 4, fromproc_stream); } if (fromstderr_needed) { fromproc_stderr_fptr = fdopen(pipe_from_stderr[0], "r"); fromproc_stderr_stream = xsb_intern_fileptr(CTXTc fromproc_stderr_fptr,callname,"pipe","r",CURRENT_CHARSET); ctop_int(CTXTc 5, fromproc_stderr_stream); } ctop_int(CTXTc 6, pid_or_status); xsb_process_table.process[tbl_pos].pid = pid_or_status; xsb_process_table.process[tbl_pos].to_stream = toproc_stream; xsb_process_table.process[tbl_pos].from_stream = fromproc_stream; xsb_process_table.process[tbl_pos].stderr_stream = fromproc_stderr_stream; concat_array(CTXTc params, " ", xsb_process_table.process[tbl_pos].cmdline,MAX_CMD_LEN); SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return TRUE; } case GET_PROCESS_TABLE: { /* sys_system(3, X). X is bound to the list of the form [process(Pid,To,From,Stderr,Cmdline), ...] */ int i; prolog_term table_term_tail, listHead; prolog_term table_term=reg_term(CTXTc 2); SYS_MUTEX_LOCK( MUTEX_SYS_SYSTEM ); init_process_table(); if (!isref(table_term)) xsb_abort("[GET_PROCESS_TABLE] Arg 1 must be a variable"); table_term_tail = table_term; for (i=0; i<MAX_SUBPROC_NUMBER; i++) { if (!FREE_PROC_TABLE_CELL(xsb_process_table.process[i].pid)) { c2p_list(CTXTc table_term_tail); /* make it into a list */ listHead = p2p_car(table_term_tail); c2p_functor(CTXTc "process", 5, listHead); c2p_int(CTXTc xsb_process_table.process[i].pid, p2p_arg(listHead,1)); c2p_int(CTXTc xsb_process_table.process[i].to_stream, p2p_arg(listHead,2)); c2p_int(CTXTc xsb_process_table.process[i].from_stream, p2p_arg(listHead,3)); c2p_int(CTXTc xsb_process_table.process[i].stderr_stream, p2p_arg(listHead,4)); c2p_string(CTXTc xsb_process_table.process[i].cmdline, p2p_arg(listHead,5)); table_term_tail = p2p_cdr(table_term_tail); } } c2p_nil(CTXTc table_term_tail); /* bind tail to nil */ SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return p2p_unify(CTXTc table_term, reg_term(CTXTc 2)); } case PROCESS_STATUS: { prolog_term pid_term=reg_term(CTXTc 2), status_term=reg_term(CTXTc 3); SYS_MUTEX_LOCK( MUTEX_SYS_SYSTEM ); init_process_table(); if (!(isointeger(pid_term))) xsb_abort("[PROCESS_STATUS] Arg 1 (process id) must be an integer"); pid = (int)oint_val(pid_term); if (!isref(status_term)) xsb_abort("[PROCESS_STATUS] Arg 2 (process status) must be a variable"); switch (process_status(pid)) { case RUNNING: c2p_string(CTXTc "running", status_term); break; case STOPPED: c2p_string(CTXTc "stopped", status_term); break; case EXITED_NORMALLY: c2p_string(CTXTc "exited_normally", status_term); break; case EXITED_ABNORMALLY: c2p_string(CTXTc "exited_abnormally", status_term); break; case ABORTED: c2p_string(CTXTc "aborted", status_term); break; case INVALID: c2p_string(CTXTc "invalid", status_term); break; default: c2p_string(CTXTc "unknown", status_term); } SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return TRUE; } case PROCESS_CONTROL: { /* sys_system(PROCESS_CONTROL, +Pid, +Signal). Signal: wait, kill */ int status; prolog_term pid_term=reg_term(CTXTc 2), signal_term=reg_term(CTXTc 3); SYS_MUTEX_LOCK( MUTEX_SYS_SYSTEM ); init_process_table(); if (!(isointeger(pid_term))) xsb_abort("[PROCESS_CONTROL] Arg 1 (process id) must be an integer"); pid = (int)oint_val(pid_term); if (isstring(signal_term) && strcmp(string_val(signal_term), "kill")==0) { if (KILL_FAILED(pid)) { SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return FALSE; } #ifdef WIN_NT CloseHandle((HANDLE) pid); #endif SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return TRUE; } if (isconstr(signal_term) && strcmp(p2c_functor(signal_term),"wait") == 0 && p2c_arity(signal_term)==1) { int exit_status; if (WAIT(pid, status) < 0) { SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return FALSE; } #ifdef WIN_NT exit_status = status; #else if (WIFEXITED(status)) exit_status = WEXITSTATUS(status); else exit_status = -1; #endif p2p_unify(CTXTc p2p_arg(signal_term,1), makeint(exit_status)); SYS_MUTEX_UNLOCK( MUTEX_SYS_SYSTEM ); return TRUE; } xsb_warn(CTXTc "[PROCESS_CONTROL] Arg 2: Invalid signal specification. Must be `kill' or `wait(Var)'"); return FALSE; } case LIST_DIRECTORY: { /* assume all type- and mode-checking is done in Prolog */ prolog_term handle = reg_term(CTXTc 2); /* ref for handle */ char *dir_name = ptoc_longstring(CTXTc 3); /* +directory name */ prolog_term filename = reg_term(CTXTc 4); /* reference for name of file */ if (is_var(handle)) return xsb_find_first_file(CTXTc handle,dir_name,filename); else return xsb_find_next_file(CTXTc handle,dir_name,filename); } default: xsb_abort("[SYS_SYSTEM] Wrong call number (an XSB bug)"); } /* end case */ return TRUE; }
/* in order to save builtin numbers, create a single socket function with * options socket_request(SockOperation,....) */ xsbBool xsb_socket_request(CTXTdecl) { int ecode = 0; /* error code for socket ops */ int timeout_flag; SOCKET sock_handle; int domain, portnum; SOCKADDR_IN socket_addr; struct linger sock_linger_opt; int rc; char *message_buffer = NULL; /* initialized to keep compiler happy */ UInteger msg_len = 0; /* initialized to keep compiler happy */ char char_read; switch (ptoc_int(CTXTc 1)) { case SOCKET_ROOT: /* this is the socket() request */ /* socket_request(SOCKET_ROOT,+domain,-socket_fd,-Error,_,_,_) Currently only AF_INET domain */ domain = (int)ptoc_int(CTXTc 2); if (!translate_domain(domain, &domain)) { return FALSE; } sock_handle = socket(domain, SOCK_STREAM, IPPROTO_TCP); /* error handling */ if (BAD_SOCKET(sock_handle)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_REQUEST"); } else { ecode = SOCK_OK; } ctop_int(CTXTc 3, (SOCKET) sock_handle); return set_error_code(CTXTc ecode, 4, "SOCKET_REQUEST"); case SOCKET_BIND: /* socket_request(SOCKET_BIND,+domain,+sock_handle,+port,-Error,_,_) Currently only supports AF_INET */ sock_handle = (SOCKET) ptoc_int(CTXTc 3); portnum = (int)ptoc_int(CTXTc 4); domain = (int)ptoc_int(CTXTc 2); if (!translate_domain(domain, &domain)) { return FALSE; } /* Bind server to the agreed upon port number. ** See commdef.h for the actual port number. */ FillWithZeros(socket_addr); socket_addr.sin_port = htons((unsigned short)portnum); socket_addr.sin_family = AF_INET; #ifndef WIN_NT socket_addr.sin_addr.s_addr = htonl(INADDR_ANY); #endif rc = bind(sock_handle, (PSOCKADDR) &socket_addr, sizeof(socket_addr)); /* error handling */ if (SOCKET_OP_FAILED(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_BIND"); } else ecode = SOCK_OK; return set_error_code(CTXTc ecode, 5, "SOCKET_BIND"); case SOCKET_LISTEN: /* socket_request(SOCKET_LISTEN,+sock_handle,+length,-Error,_,_,_) */ sock_handle = (SOCKET) ptoc_int(CTXTc 2); rc = listen(sock_handle, (int)ptoc_int(CTXTc 3)); /* error handling */ if (SOCKET_OP_FAILED(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_LISTEN"); } else ecode = SOCK_OK; return set_error_code(CTXTc ecode, 4, "SOCKET_LISTEN"); case SOCKET_ACCEPT: timeout_flag = socket_accept(CTXTc (SOCKET *)&rc, (int)pflags[SYS_TIMER]); if (timeout_flag == TIMED_OUT) { return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND"); } else { /* error handling */ if (BAD_SOCKET(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_ACCEPT"); sock_handle = rc; /* shut up warning */ } else { sock_handle = rc; /* accept() returns sock_out */ ecode = SOCK_OK; } ctop_int(CTXTc 3, (SOCKET) sock_handle); return set_error_code(CTXTc ecode, 4, "SOCKET_ACCEPT"); } case SOCKET_CONNECT: { /* socket_request(SOCKET_CONNECT,+domain,+sock_handle,+port, +hostname,-Error) */ timeout_flag = socket_connect(CTXTc &rc, (int)pflags[SYS_TIMER]); if (timeout_flag == TIMED_OUT) { return set_error_code(CTXTc TIMEOUT_ERR, 6, "SOCKET_CONNECT"); } else if (timeout_flag == TIMER_SETUP_ERR) { return set_error_code(CTXTc TIMER_SETUP_ERR, 6, "SOCKET_CONNECT"); } else { /* error handling */ if (SOCKET_OP_FAILED(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_CONNECT"); /* close, because if connect() fails then socket becomes unusable */ closesocket(ptoc_int(CTXTc 3)); } else { ecode = SOCK_OK; } return set_error_code(CTXTc ecode, 6, "SOCKET_CONNECT"); } } case SOCKET_CLOSE: /* socket_request(SOCKET_CLOSE,+sock_handle,-Error,_,_,_,_) */ sock_handle = (SOCKET)ptoc_int(CTXTc 2); /* error handling */ rc = closesocket(sock_handle); if (SOCKET_OP_FAILED(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_CLOSE"); } else ecode = SOCK_OK; return set_error_code(CTXTc ecode, 3, "SOCKET_CLOSE"); case SOCKET_RECV: /* socket_request(SOCKET_RECV,+Sockfd, -Msg, -Error,_,_,_) */ // TODO: consider adding protection against interrupts, EINTR, like // in socket_get0. timeout_flag = socket_recv(CTXTc &rc, &message_buffer, &msg_len, (int)pflags[SYS_TIMER]); if (timeout_flag == TIMED_OUT) { return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND"); } else { /* error handling */ switch (rc) { case SOCK_OK: ecode = SOCK_OK; break; case SOCK_READMSG_FAILED: ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_RECV"); break; case SOCK_READMSG_EOF: ecode = SOCK_EOF; break; case SOCK_HEADER_LEN_MISMATCH: ecode = XSB_SOCKET_ERRORCODE; break; default: xsb_abort("XSB bug: [SOCKET_RECV] invalid return code from readmsg"); } if (message_buffer != NULL) { /* use message_buffer+XSB_MSG_HEADER_LENGTH because the first XSB_MSG_HEADER_LENGTH bytes are for the message length header */ ctop_string(CTXTc 3, (char*)message_buffer+XSB_MSG_HEADER_LENGTH); mem_dealloc(message_buffer,msg_len,OTHER_SPACE); } else { /* this happens at the end of a file */ ctop_string(CTXTc 3, (char*)""); } return set_error_code(CTXTc ecode, 4, "SOCKET_RECV"); } case SOCKET_SEND: /* socket_request(SOCKET_SEND,+Sockfd, +Msg, -Error,_,_,_) */ timeout_flag = socket_send(CTXTc &rc, (int)pflags[SYS_TIMER]); if (timeout_flag == TIMED_OUT) { return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND"); } else { /* error handling */ if (SOCKET_OP_FAILED(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_SEND"); } else { ecode = SOCK_OK; } return set_error_code(CTXTc ecode, 4, "SOCKET_SEND"); } case SOCKET_GET0: /* socket_request(SOCKET_GET0,+Sockfd,-C,-Error,_,_,_) */ message_buffer = &char_read; timeout_flag = socket_get0(CTXTc &rc, message_buffer, (int)pflags[SYS_TIMER]); if (timeout_flag == TIMED_OUT) { return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND"); } else { /*error handling */ switch (rc) { case 1: ctop_int(CTXTc 3,(unsigned char)message_buffer[0]); ecode = SOCK_OK; break; case 0: ecode = SOCK_EOF; break; default: ctop_int(CTXTc 3,-1); perror("SOCKET_GET0"); ecode = XSB_SOCKET_ERRORCODE; } return set_error_code(CTXTc ecode, 4, "SOCKET_GET0"); } case SOCKET_PUT: /* socket_request(SOCKET_PUT,+Sockfd,+C,-Error_,_,_) */ timeout_flag = socket_put(CTXTc &rc, (int)pflags[SYS_TIMER]); if (timeout_flag == TIMED_OUT) { return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND"); } else { /* error handling */ if (rc == 1) { ecode = SOCK_OK; } else if (SOCKET_OP_FAILED(rc)) { ecode = XSB_SOCKET_ERRORCODE; perror("SOCKET_PUT"); } return set_error_code(CTXTc ecode, 4, "SOCKET_PUT"); } case SOCKET_SET_OPTION: { /* socket_request(SOCKET_SET_OPTION,+Sockfd,+OptionName,+Value,_,_,_) */ char *option_name = ptoc_string(CTXTc 3); sock_handle = (SOCKET)ptoc_int(CTXTc 2); /* Set the "linger" parameter to a small number of seconds */ if (0==strcmp(option_name,"linger")) { int linger_time=(int)ptoc_int(CTXTc 4); if (linger_time < 0) { sock_linger_opt.l_onoff = FALSE; sock_linger_opt.l_linger = 0; } else { sock_linger_opt.l_onoff = TRUE; sock_linger_opt.l_linger = linger_time; } if (SETSOCKOPT(sock_handle, SOL_SOCKET, SO_LINGER, &sock_linger_opt, sizeof(sock_linger_opt)) < 0) { xsb_warn(CTXTc "[SOCKET_SET_OPTION] Cannot set socket linger time"); return FALSE; } }else { xsb_warn(CTXTc "[SOCKET_SET_OPTION] Invalid option, `%s'", option_name); return FALSE; } return TRUE; } case SOCKET_SET_SELECT: { /*socket_request(SOCKET_SET_SELECT,+connection_name, +R_sockfd,+W_sockfd,+E_sockfd) */ prolog_term R_sockfd, W_sockfd, E_sockfd; int i, connection_count; int rmax_fd=0, wmax_fd=0, emax_fd=0; char *connection_name = ptoc_string(CTXTc 2); /* bind fds to input arguments */ R_sockfd = reg_term(CTXTc 3); W_sockfd = reg_term(CTXTc 4); E_sockfd = reg_term(CTXTc 5); /* initialize the array of connect_t structure for select call */ init_connections(CTXT); SYS_MUTEX_LOCK(MUTEX_SOCKETS); /* check whether the same connection name exists */ for (i=0;i<MAXCONNECT;i++) { if ((connections[i].empty_flag==FALSE) && (strcmp(connection_name,connections[i].connection_name)==0)) xsb_abort("[SOCKET_SET_SELECT] Connection `%s' already exists!", connection_name); } /* check whether there is empty slot left for connection */ if ((connection_count=checkslot())<MAXCONNECT) { if (connections[connection_count].connection_name == NULL) { connections[connection_count].connection_name = connection_name; connections[connection_count].empty_flag = FALSE; /* call the utility function separately to take the fds in */ list_sockfd(R_sockfd, &connections[connection_count].readset, &rmax_fd, &connections[connection_count].read_fds, &connections[connection_count].sizer); list_sockfd(W_sockfd, &connections[connection_count].writeset, &wmax_fd, &connections[connection_count].write_fds, &connections[connection_count].sizew); list_sockfd(E_sockfd, &connections[connection_count].exceptionset, &emax_fd,&connections[connection_count].exception_fds, &connections[connection_count].sizee); connections[connection_count].maximum_fd = xsb_max(xsb_max(rmax_fd,wmax_fd), emax_fd); } else /* if this one is reached, it is probably a bug */ xsb_abort("[SOCKET_SET_SELECT] All connections are busy!"); } else xsb_abort("[SOCKET_SET_SELECT] Max number of collections exceeded!"); SYS_MUTEX_UNLOCK(MUTEX_SOCKETS); return TRUE; } case SOCKET_SELECT: { /* socket_request(SOCKET_SELECT,+connection_name, +timeout -avail_rsockfds,-avail_wsockfds, -avail_esockfds,-ecode) Returns 3 prolog_terms for available socket fds */ prolog_term Avail_rsockfds, Avail_wsockfds, Avail_esockfds; prolog_term Avail_rsockfds_tail, Avail_wsockfds_tail, Avail_esockfds_tail; int maxfd; int i; /* index for connection_count */ char *connection_name = ptoc_string(CTXTc 2); struct timeval *tv; prolog_term timeout_term; int timeout =0; int connectname_found = FALSE; int count=0; SYS_MUTEX_LOCK(MUTEX_SOCKETS); /* specify the time out */ timeout_term = reg_term(CTXTc 3); if (isointeger(timeout_term)) { timeout = (int)oint_val(timeout_term); /* initialize tv */ tv = (struct timeval *)mem_alloc(sizeof(struct timeval),LEAK_SPACE); tv->tv_sec = timeout; tv->tv_usec = 0; } else tv = NULL; /* no timeouts */ /* initialize the prolog term */ Avail_rsockfds = p2p_new(CTXT); Avail_wsockfds = p2p_new(CTXT); Avail_esockfds = p2p_new(CTXT); /* bind to output arguments */ Avail_rsockfds = reg_term(CTXTc 4); Avail_wsockfds = reg_term(CTXTc 5); Avail_esockfds = reg_term(CTXTc 6); Avail_rsockfds_tail = Avail_rsockfds; Avail_wsockfds_tail = Avail_wsockfds; Avail_esockfds_tail = Avail_esockfds; /* // This was wrong. Lists are now made inside test_ready() c2p_list(CTXTc Avail_rsockfds_tail); c2p_list(CTXTc Avail_wsockfds_tail); c2p_list(CTXTc Avail_esockfds_tail); */ for (i=0; i < MAXCONNECT; i++) { /* find the matching connection_name to select */ if(connections[i].empty_flag==FALSE) { if (strcmp(connection_name, connections[i].connection_name) == 0) { connectname_found = TRUE; count = i; break; } } } if( i >= MAXCONNECT ) /* if no matching connection_name */ xsb_abort("[SOCKET_SELECT] connection `%s' doesn't exist", connection_name); /* compute maxfd for select call */ maxfd = connections[count].maximum_fd + 1; /* FD_SET all sockets */ set_sockfd( CTXTc count ); /* test whether the socket fd is available */ rc = select(maxfd, &connections[count].readset, &connections[count].writeset, &connections[count].exceptionset, tv); /* error handling */ if (rc == 0) /* timed out */ ecode = TIMEOUT_ERR; else if (SOCKET_OP_FAILED(rc)) { perror("SOCKET_SELECT"); ecode = XSB_SOCKET_ERRORCODE; } else { /* no error */ ecode = SOCK_OK; /* call the utility function to return the available socket fds */ test_ready(CTXTc &Avail_rsockfds_tail, &connections[count].readset, connections[count].read_fds,connections[count].sizer); test_ready(CTXTc &Avail_wsockfds_tail, &connections[count].writeset, connections[count].write_fds,connections[count].sizew); test_ready(CTXTc &Avail_esockfds_tail,&connections[count].exceptionset, connections[count].exception_fds,connections[count].sizee); } SYS_MUTEX_UNLOCK(MUTEX_SOCKETS); if (tv) mem_dealloc((struct timeval *)tv,sizeof(struct timeval),LEAK_SPACE); SQUASH_LINUX_COMPILER_WARN(connectname_found) ; return set_error_code(CTXTc ecode, 7, "SOCKET_SELECT"); } case SOCKET_SELECT_DESTROY: { /*socket_request(SOCKET_SELECT_DESTROY, +connection_name) */ char *connection_name = ptoc_string(CTXTc 2); select_destroy(CTXTc connection_name); return TRUE; } default: xsb_warn(CTXTc "[SOCKET_REQUEST] Invalid socket request %d", (int) ptoc_int(CTXTc 1)); return FALSE; } /* This trick would report a bug, if a newly added case doesn't have a return clause */ xsb_bug("SOCKET_REQUEST case %d has no return clause", ptoc_int(CTXTc 1)); }
void print_detailed_tablespace_stats(CTXTdecl) { NodeStats abtn, /* Asserted Basic Trie Nodes */ btn, /* Basic Trie Nodes */ aln, /* Answer List Nodes */ varsf, /* Variant Subgoal Frames */ asi; /* Answer Subgoal Information */ HashStats abtht, /* Asserted Basic Trie Hash Tables */ btht; /* Basic Trie Hash Tables */ NodeStats pri_tstn, /* Private Time Stamp Trie Nodes */ pri_tsi, /* Private Time Stamp Indices (Index Entries/Nodes) */ pri_prodsf, /* Private Subsumptive Producer Subgoal Frames */ pri_conssf, /* Private Subsumptive Consumer Subgoal Frames */ pri_btn, /* Private Basic Trie Nodes (Tables) */ pri_assert_btn, /* Private Basic Trie Nodes (Asserts) */ pri_aln, /* Private Answer List Nodes */ pri_varsf, /* Private Variant Subgoal Frames */ pri_asi; /* Private Answer Subgoal Information */ HashStats pri_btht, /* Private Basic Trie Hash Tables (Tables) */ pri_assert_btht, /* Private Basic Trie Hash Tables (Asserts) */ pri_tstht; /* Private Time Stamp Trie Hash Tables */ size_t tablespace_alloc, tablespace_used, pri_tablespace_alloc, pri_tablespace_used, shared_tablespace_alloc, shared_tablespace_used, trieassert_alloc, trieassert_used, de_space_alloc, de_space_used, dl_space_alloc, dl_space_used, pnde_space_alloc, pnde_space_used, pri_de_space_alloc, pri_de_space_used, pri_dl_space_alloc, pri_dl_space_used, pri_pnde_space_alloc, pri_pnde_space_used; size_t num_de_blocks, num_dl_blocks, num_pnde_blocks; size_t pri_num_de_blocks, pri_num_dl_blocks, pri_num_pnde_blocks; SM_Lock(smTableBTN); btn = node_statistics(&smTableBTN); SM_Unlock(smTableBTN); SM_Lock(smTableBTHT); btht = hash_statistics(CTXTc &smTableBTHT); SM_Unlock(smTableBTHT); SM_Lock(smVarSF); varsf = subgoal_statistics(CTXTc &smVarSF); SM_Unlock(smVarSF); SM_Lock(smALN); aln = node_statistics(&smALN); SM_Unlock(smALN); SM_Lock(smASI); asi = node_statistics(&smASI); SM_Unlock(smASI); SYS_MUTEX_LOCK( MUTEX_DELAY ); de_space_alloc = allocated_de_space(current_de_block_gl,&num_de_blocks); de_space_used = de_space_alloc - unused_de_space(); dl_space_alloc = allocated_dl_space(current_dl_block_gl,&num_dl_blocks); dl_space_used = dl_space_alloc - unused_dl_space(); pnde_space_alloc = allocated_pnde_space(current_pnde_block_gl,&num_pnde_blocks); pnde_space_used = pnde_space_alloc - unused_pnde_space(); SYS_MUTEX_UNLOCK( MUTEX_DELAY ); pri_btn = node_statistics(private_smTableBTN); pri_btht = hash_statistics(CTXTc private_smTableBTHT); pri_assert_btn = node_statistics(private_smAssertBTN); pri_assert_btht = hash_statistics(CTXTc private_smAssertBTHT); pri_aln = node_statistics(private_smALN); pri_asi = node_statistics(private_smASI); pri_varsf = subgoal_statistics(CTXTc private_smVarSF); pri_prodsf = subgoal_statistics(CTXTc private_smProdSF); pri_conssf = subgoal_statistics(CTXTc private_smConsSF); pri_tstn = node_statistics(private_smTSTN); pri_tsi = node_statistics(private_smTSIN); pri_btht = hash_statistics(CTXTc private_smTableBTHT); pri_tstht = hash_statistics(CTXTc private_smTSTHT); pri_de_space_alloc = allocated_de_space(private_current_de_block,&pri_num_de_blocks); pri_de_space_used = pri_de_space_alloc - unused_de_space_private(CTXT); pri_dl_space_alloc = allocated_dl_space(private_current_dl_block,&pri_num_dl_blocks); pri_dl_space_used = pri_dl_space_alloc - unused_dl_space_private(CTXT); pri_pnde_space_alloc = allocated_pnde_space(private_current_pnde_block,&pri_num_pnde_blocks); pri_pnde_space_used = pri_pnde_space_alloc - unused_pnde_space_private(CTXT); pri_tablespace_alloc = CurrentPrivateTableSpaceAlloc(pri_btn,pri_btht,pri_varsf,pri_prodsf, pri_conssf,pri_aln,pri_tstn,pri_tstht,pri_tsi, pri_asi); pri_tablespace_used = CurrentPrivateTableSpaceUsed(pri_btn,pri_btht,pri_varsf,pri_prodsf, pri_conssf,pri_aln,pri_tstn,pri_tstht,pri_tsi, pri_asi); pri_tablespace_alloc = pri_tablespace_alloc + pri_de_space_alloc + pri_dl_space_alloc + pri_pnde_space_alloc; pri_tablespace_used = pri_tablespace_used + pri_de_space_used + pri_dl_space_used + pri_pnde_space_used; shared_tablespace_alloc = CurrentSharedTableSpaceAlloc(btn,btht,varsf,aln,asi); shared_tablespace_used = CurrentSharedTableSpaceUsed(btn,btht,varsf,aln,asi); shared_tablespace_alloc = shared_tablespace_alloc + de_space_alloc + dl_space_alloc + pnde_space_alloc; shared_tablespace_used = shared_tablespace_used + de_space_used + dl_space_used + pnde_space_used; tablespace_alloc = shared_tablespace_alloc + pri_tablespace_alloc; tablespace_used = shared_tablespace_used + pri_tablespace_used; abtn = node_statistics(&smAssertBTN); abtht = hash_statistics(CTXTc &smAssertBTHT); trieassert_alloc = NodeStats_SizeAllocNodes(abtn) + HashStats_SizeAllocTotal(abtht); trieassert_used = NodeStats_SizeUsedNodes(abtn) + HashStats_SizeUsedTotal(abtht); SQUASH_LINUX_COMPILER_WARN(trieassert_used) ; printf(" Current Total Allocation: %12"UIntfmt" bytes\n" " Current Total Usage: %12"UIntfmt" bytes\n", pspacesize[TABLE_SPACE]-trieassert_alloc, pspacesize[TABLE_SPACE]-trieassert_alloc-(tablespace_alloc-tablespace_used)); // printf("\n --------------------- Shared tables ---------------------\n"); printf("\n" "Shared Table Space Usage (exc"UIntfmt"ding asserted and interned tries) \n"); printf(" Current Total Allocation: %12"UIntfmt" bytes\n" " Current Total Usage: %12"UIntfmt" bytes\n", shared_tablespace_alloc,shared_tablespace_used); // Basic Trie Stuff if ( NodeStats_NumBlocks(btn) > 0 || HashStats_NumBlocks(btht) > 0 || NodeStats_NumBlocks(aln) > 0) { printf("\n" " Basic Tries\n"); if ( NodeStats_NumBlocks(btn) > 0) print_NodeStats(btn,"Basic Trie Nodes"); if (HashStats_NumBlocks(btht) > 0) print_HashStats(btht,"Basic Trie Hash Tables"); if ( NodeStats_NumBlocks(aln) > 0) print_NodeStats(aln,"Answer List Nodes (for Incomplete Variant Tables)"); } // Subgoal Frames if (NodeStats_NumBlocks(varsf) > 0) { printf("\n" " Subgoal Frames\n"); if (NodeStats_NumBlocks(varsf) > 0) print_NodeStats(varsf,"Variant Subgoal Frames"); } // Conditional Answers if (dl_space_alloc > 0 || de_space_alloc > 0 || pnde_space_alloc > 0 || NodeStats_NumBlocks(asi) > 0) { printf("\n" " Information for Conditional Answers in Variant Tables \n"); if (dl_space_alloc > 0) print_wfs_usage(dl_space_alloc,dl_space_used,num_dl_blocks,DLS_PER_BLOCK, sizeof(struct delay_list),"Delay Lists"); if (de_space_alloc > 0) print_wfs_usage(de_space_alloc,de_space_used,num_de_blocks,DES_PER_BLOCK, sizeof(struct delay_element),"Delay Elements"); if (pnde_space_alloc > 0) print_wfs_usage(pnde_space_alloc,pnde_space_used,num_pnde_blocks,PNDES_PER_BLOCK, sizeof(struct pos_neg_de_list),"Back-pointer Lists"); if ( NodeStats_NumBlocks(asi) > 0) print_NodeStats(asi,"Answer Substitution Frames"); } // Private trie assert space if ( NodeStats_NumBlocks(abtn) > 0 || HashStats_NumBlocks(abtht) > 0) { printf("\n ---------------- Shared Asserted and Interned Tries ----------------\n"); if ( NodeStats_NumBlocks(abtn) > 0) print_NodeStats(abtn,"Basic Trie Nodes (Assert)"); if (HashStats_NumBlocks(abtht) > 0) print_HashStats(abtht,"Basic Trie Hash Tables (Assert)"); } printf("\n --------------------- Private tables ---------------------\n"); printf("\n" "Private Table Space Usage for Thread %"Intfmt" (exc"UIntfmt"ding asserted and interned tries) \n" " Current Total Allocation: %12"UIntfmt" bytes\n" " Current Total Usage: %12"UIntfmt" bytes\n", xsb_thread_id,pri_tablespace_alloc,pri_tablespace_used); // Basic Trie Stuff if ( NodeStats_NumBlocks(pri_btn) > 0 || HashStats_NumBlocks(pri_btht) > 0 || NodeStats_NumBlocks(pri_aln) > 0) { printf("\n" " Basic Tries\n"); if ( NodeStats_NumBlocks(pri_btn) > 0) print_NodeStats(pri_btn,"Basic Trie Nodes"); if (HashStats_NumBlocks(pri_btht) > 0) print_HashStats(pri_btht,"Basic Trie Hash Tables"); if ( NodeStats_NumBlocks(pri_aln) > 0) print_NodeStats(pri_aln,"Answer List Nodes (for Incomplete Variant Tables)"); } // Subgoal Frames if (NodeStats_NumBlocks(pri_varsf) > 0 || NodeStats_NumBlocks(pri_prodsf) > 0 || NodeStats_NumBlocks(pri_conssf) > 0) { printf("\n" " Subgoal Frames\n"); if (NodeStats_NumBlocks(pri_varsf) > 0) print_NodeStats(pri_varsf,"Variant Subgoal Frames"); if (NodeStats_NumBlocks(pri_prodsf) > 0) print_NodeStats(pri_prodsf,"Producer Subgoal Frames"); if (NodeStats_NumBlocks(pri_conssf) > 0) print_NodeStats(pri_conssf,"Consumer Subgoal Frames"); } // Subsumptive Tables if ( NodeStats_NumBlocks(pri_tstn) > 0 || HashStats_NumBlocks(pri_tstht) > 0 || NodeStats_NumBlocks(pri_tsi) > 0) { printf("\n" " Time Stamp Tries (for Subsumptive Tables) \n"); if (NodeStats_NumBlocks(pri_tstn) > 0) print_NodeStats(pri_tstn,"Time Stamp Trie Nodes"); if (HashStats_NumBlocks(pri_tstht) > 0) print_HashStats(pri_tstht,"Time Stamp Trie Hash Tables"); if (NodeStats_NumBlocks(pri_tsi) > 0) print_NodeStats(pri_tsi,"Time Stamp Trie Index Nodes"); } // Conditional Answers if (pri_dl_space_alloc > 0 || pri_de_space_alloc > 0 || pri_pnde_space_alloc > 0 || NodeStats_NumBlocks(pri_asi) > 0) { printf("\n" " Information for Conditional Answers in Variant Tables \n"); if (pri_dl_space_alloc > 0) print_wfs_usage(pri_dl_space_alloc,pri_dl_space_used,pri_num_dl_blocks,DLS_PER_BLOCK, sizeof(struct delay_list),"Delay Lists"); if (pri_de_space_alloc > 0) print_wfs_usage(pri_de_space_alloc,pri_de_space_used,pri_num_de_blocks,DES_PER_BLOCK, sizeof(struct delay_element),"Delay Elements"); if (pri_pnde_space_alloc > 0) print_wfs_usage(pri_pnde_space_alloc,pri_pnde_space_used,pri_num_pnde_blocks,PNDES_PER_BLOCK, sizeof(struct pos_neg_de_list),"Back-pointer Lists"); if ( NodeStats_NumBlocks(pri_asi) > 0) print_NodeStats(pri_asi,"Answer Substitution Frames"); } // Private trie assert space if ( NodeStats_NumBlocks(pri_assert_btn) > 0 || HashStats_NumBlocks(pri_assert_btht) > 0) { printf("\n ---------------- Private Asserted and Interned Tries ----------------\n"); if ( NodeStats_NumBlocks(pri_assert_btn) > 0) print_NodeStats(pri_assert_btn,"Basic Trie Nodes (Assert)"); if (HashStats_NumBlocks(pri_assert_btht) > 0) print_HashStats(pri_assert_btht,"Basic Trie Hash Tables (Assert)"); } printf("\n"); }