fix to thread support.

This commit is contained in:
Vítor Santos Costa 2011-03-11 19:49:32 +00:00
parent 93d2ac7e59
commit e05b84ce4e
40 changed files with 222 additions and 498 deletions

View File

@ -74,6 +74,8 @@ STATIC_PROTO(void InitFlags, (void));
STATIC_PROTO(void InitCodes, (void));
STATIC_PROTO(void InitVersion, (void));
static void InitWorker(int wid);
STD_PROTO(void exit, (int));
@ -1180,6 +1182,19 @@ InitThreadHandle(int wid)
FOREIGN_ThreadHandle(wid).tdetach = (CELL)0;
FOREIGN_ThreadHandle(wid).cmod = (CELL)0;
}
int
Yap_InitThread(int new_id)
{
struct worker_local *new_s;
if (new_id) {
if (!(new_s = (struct worker_local *)calloc(sizeof(struct worker_local), 1)))
return FALSE;
Yap_WLocal[new_id] = new_s;
}
InitWorker(new_id);
return TRUE;
}
#endif
static void
@ -1232,7 +1247,7 @@ struct worker_shared Yap_Global;
#if defined(YAPOR) && !defined(THREADS)
struct worker_local *Yap_WLocal;
#elif defined(YAPOR) || defined(THREADS)
struct worker_local Yap_WLocal[MAX_AGENTS];
struct worker_local *Yap_WLocal[MAX_AGENTS];
#else
struct worker_local Yap_WLocal;
#endif
@ -1242,8 +1257,15 @@ InitCodes(void)
{
CACHE_REGS
int wid;
for (wid = 1; wid < MAX_INITS; wid++) {
#if THREADS
Yap_WLocal[wid] = NULL;
}
#endif
#include "ihstruct.h"
Yap_InitThread(0);
InitGlobal();
InitWorker(0);
InitFirstWorkerThreadHandle();
/* make sure no one else can use these two atoms */
CurrentModule = 0;
@ -1284,6 +1306,8 @@ Yap_InitWorkspace(UInt Heap, UInt Stack, UInt Trail, UInt Atts, UInt max_table_s
/* initialise system stuff */
#if PUSH_REGS
#ifdef THREADS
if (!(Yap_WLocal[0] = (struct worker_local *)calloc(sizeof(struct worker_local), 1)))
return;
pthread_key_create(&Yap_yaamregs_key, NULL);
pthread_setspecific(Yap_yaamregs_key, (const void *)&Yap_standard_regs);
Yap_master_thread = pthread_self();

View File

@ -570,17 +570,15 @@ static Int
int emacs_cares = FALSE;
#endif
Term tmod = Deref(ARG3), OCurrentModule = CurrentModule, tpos;
extern void Yap_setCurrentSourceLocation(IOSTREAM *s);
Yap_setCurrentSourceLocation(inp_stream);
if (IsVarTerm(tmod)) {
tmod = CurrentModule;
} else if (!IsAtomTerm(tmod)) {
Yap_Error(TYPE_ERROR_ATOM, tmod, "read_term/2");
return FALSE;
}
if (!(inp_stream->flags & SIO_TEXT)) {
Yap_Error(PERMISSION_ERROR_INPUT_BINARY_STREAM, StreamName(inp_stream), "read_term/2");
return FALSE;
}
Yap_Error_TYPE = YAP_NO_ERROR;
tpos = StreamPosition(inp_stream);
if (!Yap_unify(tpos,ARG5)) {

View File

@ -53,10 +53,18 @@ allocate_new_tid(void)
int new_worker_id = 0;
LOCK(ThreadHandlesLock);
while(new_worker_id < MAX_THREADS &&
Yap_WLocal[new_worker_id] &&
(FOREIGN_ThreadHandle(new_worker_id).in_use == TRUE ||
FOREIGN_ThreadHandle(new_worker_id).zombie == TRUE) )
new_worker_id++;
if (new_worker_id < MAX_THREADS) {
if (!Yap_WLocal[new_worker_id]) {
DEBUG_TLOCK_ACCESS(new_worker_id, 0);
if (!Yap_InitThread(new_worker_id)) {
return -1;
}
pthread_mutex_lock(&(FOREIGN_ThreadHandle(new_worker_id).tlock));
FOREIGN_ThreadHandle(new_worker_id).in_use = TRUE;
} else if (new_worker_id < MAX_THREADS) {
DEBUG_TLOCK_ACCESS(new_worker_id, 0);
pthread_mutex_lock(&(FOREIGN_ThreadHandle(new_worker_id).tlock));
FOREIGN_ThreadHandle(new_worker_id).in_use = TRUE;
@ -823,6 +831,7 @@ p_nof_threads( USES_REGS1 )
int i = 0, wid;
LOCK(ThreadHandlesLock);
for (wid = 0; wid < MAX_THREADS; wid++) {
if (!Yap_WLocal[wid]) break;
if (FOREIGN_ThreadHandle(wid).in_use)
i++;
}

View File

@ -188,12 +188,12 @@ extern struct worker_shared Yap_Global;
#if defined(YAPOR) || defined(THREADS)
#if defined(THREADS)
extern struct worker_local Yap_WLocal[MAX_AGENTS];
extern struct worker_local *Yap_WLocal[MAX_AGENTS];
#else
extern struct worker_local *Yap_WLocal;
#endif
#define WL (Yap_WLocal+worker_id)
#define FOREIGN_WL(wid) (Yap_WLocal+(wid))
#define WL (Yap_WLocal[worker_id])
#define FOREIGN_WL(wid) (Yap_WLocal[(wid)])
#else
extern struct worker_local Yap_WLocal;
#define WL (&Yap_WLocal)

View File

@ -354,6 +354,9 @@ void STD_PROTO(Yap_WinError,(char *));
/* threads.c */
void STD_PROTO(Yap_InitThreadPreds,(void));
#if THREADS
int STD_PROTO(Yap_InitThread,(int));
#endif
/* tracer.c */
#ifdef LOW_LEVEL_TRACER

View File

@ -156,8 +156,8 @@
#endif
#ifdef THREADS
#define ThreadHandle WL->thread_handle
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)].thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id].thread_handle)
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)]->thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id]->thread_handle)
#endif

View File

@ -158,8 +158,8 @@ typedef struct worker_local {
#endif
#ifdef THREADS
struct thandle thread_handle;
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)].thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id].thread_handle)
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)]->thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id]->thread_handle)
#endif
} w_local;

View File

@ -341,6 +341,7 @@
FunctorCsult = Yap_MkFunctor(AtomCsult,1);
FunctorCurrentModule = Yap_MkFunctor(AtomCurrentModule,1);
FunctorCutBy = Yap_MkFunctor(AtomCutBy,1);
FunctorDBREF = Yap_MkFunctor(AtomDBREF,1);
FunctorDiff = Yap_MkFunctor(AtomDiff,2);
FunctorDoLogUpdClause = Yap_MkFunctor(AtomDoLogUpdClause,6);
FunctorDoLogUpdClause0 = Yap_MkFunctor(AtomDoLogUpdClause0,6);

View File

@ -156,8 +156,8 @@ static void InitWorker(int wid) {
#endif
#ifdef THREADS
InitThreadHandle(wid);
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)].thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id].thread_handle)
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)]->thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id]->thread_handle)
#endif
}

View File

@ -341,6 +341,7 @@
FunctorCsult = FuncAdjust(FunctorCsult);
FunctorCurrentModule = FuncAdjust(FunctorCurrentModule);
FunctorCutBy = FuncAdjust(FunctorCutBy);
FunctorDBREF = FuncAdjust(FunctorDBREF);
FunctorDiff = FuncAdjust(FunctorDiff);
FunctorDoLogUpdClause = FuncAdjust(FunctorDoLogUpdClause);
FunctorDoLogUpdClause0 = FuncAdjust(FunctorDoLogUpdClause0);

View File

@ -156,8 +156,8 @@ static void RestoreWorker(int wid USES_REGS) {
#endif
#ifdef THREADS
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)].thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id].thread_handle)
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)]->thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id]->thread_handle)
#endif
}

View File

@ -680,6 +680,8 @@
#define FunctorCurrentModule Yap_heap_regs->FunctorCurrentModule_
Functor FunctorCutBy_;
#define FunctorCutBy Yap_heap_regs->FunctorCutBy_
Functor FunctorDBREF_;
#define FunctorDBREF Yap_heap_regs->FunctorDBREF_
Functor FunctorDiff_;
#define FunctorDiff Yap_heap_regs->FunctorDiff_
Functor FunctorDoLogUpdClause_;

View File

@ -26,6 +26,7 @@ index(map_assoc,2,assoc,library(assoc)).
index(map_assoc,3,assoc,library(assoc)).
index(put_assoc,4,assoc,library(assoc)).
index(del_assoc,4,assoc,library(assoc)).
index(assoc_to_keys,2,assoc,library(assoc)).
index(del_min_assoc,4,assoc,library(assoc)).
index(del_max_assoc,4,assoc,library(assoc)).
index(avl_new,1,avl,library(avl)).
@ -52,6 +53,7 @@ index(open_chars_stream,2,charsio,library(charsio)).
index(with_output_to_chars,2,charsio,library(charsio)).
index(with_output_to_chars,3,charsio,library(charsio)).
index(with_output_to_chars,4,charsio,library(charsio)).
index(term_to_atom,2,charsio,library(charsio)).
index(chr_show_store,1,chr,library(chr)).
index(find_chr_constraint,1,chr,library(chr)).
index(chr_trace,0,chr,library(chr)).
@ -169,9 +171,14 @@ index(jpl_set_element,2,jpl,library(jpl)).
index(append,3,lists,library(lists)).
index(append,2,lists,library(lists)).
index(delete,3,lists,library(lists)).
index(intersection,3,lists,library(lists)).
index(flatten,2,lists,library(lists)).
index(last,2,lists,library(lists)).
index(list_concat,2,lists,library(lists)).
index(max_list,2,lists,library(lists)).
index(member,2,lists,library(lists)).
index(memberchk,2,lists,library(lists)).
index(min_list,2,lists,library(lists)).
index(nextto,3,lists,library(lists)).
index(nth,3,lists,library(lists)).
index(nth,4,lists,library(lists)).
@ -179,6 +186,7 @@ index(nth0,3,lists,library(lists)).
index(nth0,4,lists,library(lists)).
index(nth1,3,lists,library(lists)).
index(nth1,4,lists,library(lists)).
index(numlist,3,lists,library(lists)).
index(permutation,2,lists,library(lists)).
index(prefix,2,lists,library(lists)).
index(remove_duplicates,2,lists,library(lists)).
@ -188,16 +196,11 @@ index(select,3,lists,library(lists)).
index(selectchk,3,lists,library(lists)).
index(sublist,2,lists,library(lists)).
index(substitute,4,lists,library(lists)).
index(subtract,3,lists,library(lists)).
index(suffix,2,lists,library(lists)).
index(sum_list,2,lists,library(lists)).
index(sum_list,3,lists,library(lists)).
index(suffix,2,lists,library(lists)).
index(sumlist,2,lists,library(lists)).
index(list_concat,2,lists,library(lists)).
index(flatten,2,lists,library(lists)).
index(max_list,2,lists,library(lists)).
index(min_list,2,lists,library(lists)).
index(numlist,3,lists,library(lists)).
index(intersection,3,lists,library(lists)).
index(nb_queue,1,nb,library(nb)).
index(nb_queue,2,nb,library(nb)).
index(nb_queue_close,3,nb,library(nb)).
@ -232,6 +235,8 @@ index(option,2,swi_option,library(option)).
index(option,3,swi_option,library(option)).
index(select_option,3,swi_option,library(option)).
index(select_option,4,swi_option,library(option)).
index(merge_options,3,swi_option,library(option)).
index(meta_options,3,swi_option,library(option)).
index(list_to_ord_set,2,ordsets,library(ordsets)).
index(merge,3,ordsets,library(ordsets)).
index(ord_add_element,3,ordsets,library(ordsets)).
@ -335,14 +340,12 @@ index(ord_list_to_rbtree,2,rbtrees,library(rbtrees)).
index(is_rbtree,1,rbtrees,library(rbtrees)).
index(rb_size,2,rbtrees,library(rbtrees)).
index(rb_in,3,rbtrees,library(rbtrees)).
index(read_line_to_codes,2,readutil,library(readutil)).
index(read_line_to_codes,3,readutil,library(readutil)).
index(read_stream_to_codes,2,readutil,library(readutil)).
index(read_stream_to_codes,3,readutil,library(readutil)).
index(read_file_to_codes,2,readutil,library(readutil)).
index(read_file_to_codes,3,readutil,library(readutil)).
index(read_file_to_terms,2,readutil,library(readutil)).
index(read_file_to_terms,3,readutil,library(readutil)).
index(read_line_to_codes,2,read_util,library(readutil)).
index(read_line_to_codes,3,read_util,library(readutil)).
index(read_stream_to_codes,2,read_util,library(readutil)).
index(read_stream_to_codes,3,read_util,library(readutil)).
index(read_file_to_codes,3,read_util,library(readutil)).
index(read_file_to_terms,3,read_util,library(readutil)).
index(regexp,3,regexp,library(regexp)).
index(regexp,4,regexp,library(regexp)).
index(load_foreign_library,1,shlib,library(shlib)).
@ -380,6 +383,7 @@ index(system,2,operating_system_support,library(system)).
index(mktime,2,operating_system_support,library(system)).
index(tmpnam,1,operating_system_support,library(system)).
index(tmp_file,2,operating_system_support,library(system)).
index(tmpdir,1,operating_system_support,library(system)).
index(wait,2,operating_system_support,library(system)).
index(working_directory,2,operating_system_support,library(system)).
index(term_hash,2,terms,library(terms)).
@ -390,7 +394,6 @@ index(unifiable,3,terms,library(terms)).
index(subsumes,2,terms,library(terms)).
index(subsumes_chk,2,terms,library(terms)).
index(cyclic_term,1,terms,library(terms)).
index(acyclic_term,1,terms,library(terms)).
index(variable_in_term,2,terms,library(terms)).
index(variables_within_term,3,terms,library(terms)).
index(new_variables_in_term,3,terms,library(terms)).

View File

@ -96,9 +96,7 @@ DIALECT_PROGRAMS= \
DIALECT_SWI= \
$(srcdir)/dialect/swi/INDEX.pl \
$(srcdir)/dialect/swi/listing.pl \
$(srcdir)/dialect/swi/readutil.pl
$(srcdir)/dialect/swi/listing.pl
install: $(PROGRAMS) install_myddas
mkdir -p $(DESTDIR)$(SHAREDIR)/Yap

View File

@ -64,8 +64,7 @@
[datime/1,
mktime/2,
file_property/2,
delete_file/1,
sleep/1]).
delete_file/1]).
:- reexport(library(arg),
[genarg/3]).
@ -104,19 +103,6 @@ goal_expansion(atom_concat(A,B),atomic_concat(A,B)).
goal_expansion(atom_concat(A,B,C),atomic_concat(A,B,C)).
%goal_expansion(arg(A,_,_),_) :- nonvar(A), !, fail.
goal_expansion(arg(A,B,C),genarg(A,B,C)).
goal_expansion(time_file(A,B),system:swi_time_file(A,B)).
goal_expansion(stamp_date_time(A,B,C),system:swi_stamp_date_time(A,B,C)).
goal_expansion(date_time_stamp(A,B),system:swi_date_time_stamp(A,B)).
goal_expansion(format_time(A,B,C),system:swi_format_time(A,B,C)).
goal_expansion(format_time(A,B,C,D),system:swi_format_time(A,B,C,D)).
goal_expansion(get_time(A),system:swi_get_time(A)).
goal_expansion(time_file(A,B),system:swi_time_file(A,B)).
goal_expansion(expand_file_name(A,B),system:swi_expand_file_name(A,B)).
goal_expansion(wildcard_match(A,B),system:swi_wilcard_match(A,B)).
goal_expansion(directory_files(A,B),system:swi_directory_files(A,B)).
goal_expansion(exists_file(A), system:swi_exists_file(A)).
goal_expansion(exists_directory(A), system:swi_exists_directory(A)).
% make sure we also use
:- user:library_directory(X),

View File

@ -30,7 +30,7 @@ index(partition,5,system,library(dialect/swi)).
index(datime,1,system,library(dialect/swi)).
index(mktime,2,system,library(dialect/swi)).
index(file_property,2,system,library(dialect/swi)).
index(sleep,1,system,library(dialect/swi)).
index(delete_file,1,system,library(dialect/swi)).
index(genarg,3,system,library(dialect/swi)).
index(subsumes,2,system,library(dialect/swi)).
index(subsumes_chk,2,system,library(dialect/swi)).
@ -41,17 +41,20 @@ index(variant,2,system,library(dialect/swi)).
index(concat_atom,2,system,library(dialect/swi)).
index(concat_atom,3,system,library(dialect/swi)).
index(setenv,2,system,library(dialect/swi)).
index(prolog_to_os_filename,2,system,library(dialect/swi)).
index(is_absolute_file_name,1,system,library(dialect/swi)).
index(read_clause,1,system,library(dialect/swi)).
index(string,1,system,library(dialect/swi)).
index(working_directory,2,system,library(dialect/swi)).
index(chdir,1,system,library(dialect/swi)).
index(compile_aux_clauses,1,system,library(dialect/swi)).
index(convert_time,2,system,library(dialect/swi)).
index('$set_source_module',2,system,library(dialect/swi)).
index('$declare_module',5,system,library(dialect/swi)).
index('$set_predicate_attribute',3,system,library(dialect/swi)).
index(stamp_date_time,3,system,library(dialect/swi)).
index(date_time_stamp,2,system,library(dialect/swi)).
index(format_time,3,system,library(dialect/swi)).
index(format_time,4,system,library(dialect/swi)).
index(time_file,2,system,library(dialect/swi)).
index(flag,3,system,library(dialect/swi)).
index(require,1,system,library(dialect/swi)).
index(normalize_space,2,system,library(dialect/swi)).
index(current_flag,1,system,library(dialect/swi)).

View File

@ -98,6 +98,9 @@ PL_unify_blob(term_t t, void *blob, size_t len, PL_blob_t *type)
if (!ae) {
return FALSE;
}
if (type->acquire) {
type->acquire(AtomToSWIAtom(AbsAtom(ae)));
}
return Yap_unify(Yap_GetFromSlot(t PASS_REGS), MkAtomTerm(AbsAtom(ae)));
}

View File

@ -1360,38 +1360,6 @@ X_API int PL_unify_wchars(term_t t, int type, size_t len, const pl_wchar_t *char
return YAP_Unify(Yap_GetFromSlot(t PASS_REGS), chterm);
}
/* SWI: int PL_unify_wchars(term_t ?t, int type, size_t len,, const pl_wchar_t *s)
*/
X_API int PL_unify_wchars_diff(term_t t, term_t tail, int type, size_t len, const pl_wchar_t *chars)
{
CACHE_REGS
YAP_Term chterm;
if (tail == 0)
return PL_unify_wchars(t, type, len, chars);
if (Unsigned(H) > Unsigned(ASP)-CreepFlag) {
if (!Yap_gc(0, ENV, CP)) {
return FALSE;
}
}
if (len == (size_t)-1)
len = wcslen(chars);
switch (type) {
case PL_CODE_LIST:
chterm = YAP_NWideBufferToDiffList(chars, Yap_GetFromSlot(tail PASS_REGS), len);
break;
case PL_CHAR_LIST:
chterm = YAP_NWideBufferToAtomDiffList(chars, Yap_GetFromSlot(tail PASS_REGS), len);
break;
default:
fprintf(stderr,"NOT GOOD option %d PL_unify_chars_wdiff\n",type);
/* should give error?? */
return FALSE;
}
return YAP_Unify(Yap_GetFromSlot(t PASS_REGS), chterm);
}
typedef struct {
int type;
union {
@ -2528,7 +2496,7 @@ X_API int
PL_destroy_engine(PL_engine_t e)
{
#if THREADS
return YAP_ThreadDestroyEngine((struct worker_local *)e-Yap_WLocal);
return YAP_ThreadDestroyEngine(((struct worker_local *)e)->thread_handle.current_yaam_regs->worker_id_);
#else
return FALSE;
#endif
@ -2542,7 +2510,7 @@ PL_set_engine(PL_engine_t engine, PL_engine_t *old)
int cwid = PL_thread_self(), nwid;
if (cwid >= 0) {
if (old) *old = (PL_engine_t)(Yap_WLocal+cwid);
if (old) *old = (PL_engine_t)(Yap_WLocal[cwid]);
}
if (!engine) {
if (cwid < 0)
@ -2561,7 +2529,7 @@ PL_set_engine(PL_engine_t engine, PL_engine_t *old)
}
return PL_ENGINE_SET;
} else {
nwid = (struct worker_local *)engine-Yap_WLocal;
nwid = ((struct worker_local *)engine)->thread_handle.current_yaam_regs->worker_id_;
}
pthread_mutex_lock(&(FOREIGN_ThreadHandle(nwid).tlock));
@ -2779,6 +2747,8 @@ PL_query(int query)
return (intptr_t)Yap_argv;
case PL_QUERY_USER_CPU:
return (intptr_t)Yap_cputime();
case PL_QUERY_VERSION:
return (intptr_t)600301;
default:
fprintf(stderr,"Unimplemented PL_query %d\n",query);
return (intptr_t)0;
@ -3002,6 +2972,10 @@ term_t Yap_CvtTerm(term_t ts)
default:
return ts;
}
} else if (f == FunctorDBRef) {
Term ta[0];
ta[0] = MkIntegerTerm(DBRefOfTerm(t));
return Yap_InitSlot(Yap_MkApplTerm(FunctorDBREF, 1, ta) PASS_REGS);
}
}
}

View File

@ -1,242 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(read_util,
[ read_line_to_codes/2, % +Fd, -Codes (without trailing \n)
read_line_to_codes/3, % +Fd, -Codes, ?Tail
read_stream_to_codes/2, % +Fd, -Codes
read_stream_to_codes/3, % +Fd, -Codes, ?Tail
read_file_to_codes/3, % +File, -Codes, +Options
read_file_to_terms/3 % +File, -Terms, +Options
]).
:- use_module(library(shlib)).
:- use_module(library(lists), [select/3]).
:- use_module(library(error)).
/** <module> Read utilities
This library provides some commonly used reading predicates. As these
predicates have proven to be time-critical in some applications we moved
them to C. For compatibility as well as to reduce system dependency, we
link the foreign code at runtime and fallback to the Prolog
implementation if the shared object cannot be found.
*/
:- volatile
read_line_to_codes/2,
read_line_to_codes/3,
read_stream_to_codes/2,
read_stream_to_codes/3.
link_foreign :-
catch(load_foreign_library(foreign(readutil)), _, fail), !.
link_foreign :-
assertz((read_line_to_codes(Stream, Line) :-
pl_read_line_to_codes(Stream, Line))),
assertz((read_line_to_codes(Stream, Line, Tail) :-
pl_read_line_to_codes(Stream, Line, Tail))),
assertz((read_stream_to_codes(Stream, Content) :-
pl_read_stream_to_codes(Stream, Content))),
assertz((read_stream_to_codes(Stream, Content, Tail) :-
pl_read_stream_to_codes(Stream, Content, Tail))),
compile_predicates([ read_line_to_codes/2,
read_line_to_codes/3,
read_stream_to_codes/2,
read_stream_to_codes/3
]).
:- initialization(link_foreign, now).
/*******************************
* LINES *
*******************************/
%% read_line_to_codes(+In:stream, -Line:codes) is det.
%
% Read a line of input from In into a list of character codes.
% Trailing newline and or return are deleted. Upon reaching
% end-of-file Line is unified to the atom =end_of_file=.
pl_read_line_to_codes(Fd, Codes) :-
get_code(Fd, C0),
( C0 == -1
-> Codes = end_of_file
; read_1line_to_codes(C0, Fd, Codes0)
),
Codes = Codes0.
read_1line_to_codes(-1, _, []) :- !.
read_1line_to_codes(10, _, []) :- !.
read_1line_to_codes(13, Fd, L) :- !,
get_code(Fd, C2),
read_1line_to_codes(C2, Fd, L).
read_1line_to_codes(C, Fd, [C|T]) :-
get_code(Fd, C2),
read_1line_to_codes(C2, Fd, T).
%% read_line_to_codes(+Fd, -Line, ?Tail) is det.
%
% Read a line of input as a difference list. This should be used
% to read multiple lines efficiently. On reaching end-of-file,
% Tail is bound to the empty list.
pl_read_line_to_codes(Fd, Codes, Tail) :-
get_code(Fd, C0),
read_line_to_codes(C0, Fd, Codes0, Tail),
Codes = Codes0.
read_line_to_codes(-1, _, Tail, Tail) :- !,
Tail = [].
read_line_to_codes(10, _, [10|Tail], Tail) :- !.
read_line_to_codes(C, Fd, [C|T], Tail) :-
get_code(Fd, C2),
read_line_to_codes(C2, Fd, T, Tail).
/*******************************
* STREAM (ENTIRE INPUT) *
*******************************/
%% read_stream_to_codes(+Stream, -Codes) is det.
%% read_stream_to_codes(+Stream, -Codes, ?Tail) is det.
%
% Read input from Stream to a list of character codes. The version
% read_stream_to_codes/3 creates a difference-list.
pl_read_stream_to_codes(Fd, Codes) :-
pl_read_stream_to_codes(Fd, Codes, []).
pl_read_stream_to_codes(Fd, Codes, Tail) :-
get_code(Fd, C0),
read_stream_to_codes(C0, Fd, Codes0, Tail),
Codes = Codes0.
read_stream_to_codes(-1, _, Tail, Tail) :- !.
read_stream_to_codes(C, Fd, [C|T], Tail) :-
get_code(Fd, C2),
read_stream_to_codes(C2, Fd, T, Tail).
%% read_stream_to_terms(+Stream, -Terms, ?Tail, +Options) is det.
read_stream_to_terms(Fd, Terms, Tail, Options) :-
read_term(Fd, C0, Options),
read_stream_to_terms(C0, Fd, Terms0, Tail, Options),
Terms = Terms0.
read_stream_to_terms(end_of_file, _, Tail, Tail, _) :- !.
read_stream_to_terms(C, Fd, [C|T], Tail, Options) :-
read_term(Fd, C2, Options),
read_stream_to_terms(C2, Fd, T, Tail, Options).
/*******************************
* FILE (ENTIRE INPUT) *
*******************************/
%% read_file_to_codes(+Spec, -Codes, +Options) is det.
%
% Read the file Spec into a list of Codes. Options is split into
% options for absolute_file_name/3 and open/4.
read_file_to_codes(Spec, Codes, Options) :-
must_be(proper_list, Options),
( select(tail(Tail), Options, Options1)
-> true
; Tail = [],
Options1 = Options
),
split_options(Options1, file_option, FileOptions, OpenOptions),
absolute_file_name(Spec,
[ access(read)
| FileOptions
],
Path),
open(Path, read, Fd, OpenOptions),
call_cleanup(read_stream_to_codes(Fd, Codes0, Tail),
close(Fd)),
Codes = Codes0.
%% read_file_to_terms(+Spec, -Terms, +Options) is det.
%
% Read the file Spec into a list of terms. Options is split over
% absolute_file_name/3, open/4 and read_term/3.
read_file_to_terms(Spec, Terms, Options) :-
must_be(proper_list, Options),
( select(tail(Tail), Options, Options1)
-> true
; Tail = [],
Options1 = Options
),
split_options(Options1, file_option, FileOptions, Options2),
split_options(Options2, read_option, ReadOptions, OpenOptions),
absolute_file_name(Spec,
[ access(read)
| FileOptions
],
Path),
open(Path, read, Fd, OpenOptions),
call_cleanup(read_stream_to_terms(Fd, Terms0, Tail, ReadOptions),
close(Fd)),
Terms = Terms0.
split_options([], _, [], []).
split_options([H|T], G, File, Open) :-
( call(G, H)
-> File = [H|FT],
OT = Open
; Open = [H|OT],
FT = File
),
split_options(T, G, FT, OT).
read_option(module(_)).
read_option(syntax_errors(_)).
read_option(character_escapes(_)).
read_option(double_quotes(_)).
read_option(backquoted_string(_)).
file_option(extensions(_)).
file_option(file_type(_)).
file_option(file_errors(_)).
file_option(relative_to(_)).
file_option(expand(_)).
/*******************************
* XREF *
*******************************/
:- multifile prolog:meta_goal/2.
:- dynamic prolog:meta_goal/2.
prolog:meta_goal(split_options(_,G,_,_), [G+1]).

View File

@ -88,79 +88,6 @@ check_int(I, Inp) :-
% file operations
delete_file(IFile) :-
true_file_name(IFile, File),
delete_file(File, off, on, off).
delete_file(IFile, Opts) :-
true_file_name(IFile, File),
process_delete_file_opts(Opts, Dir, Recurse, Ignore, delete_file(File,Opts)),
delete_file(File, Dir, Recurse, Ignore).
process_delete_file_opts(V, _, _, _, T) :- var(V), !,
throw(error(instantiation_error,T)).
process_delete_file_opts([], off, off, off, _) :- !.
process_delete_file_opts([V|_], _, _, _, T) :- var(V), !,
throw(error(instantiation_error,T)).
process_delete_file_opts([directory|Opts], on, Recurse, Ignore, T) :- !,
process_delete_file_opts(Opts, _, Recurse, Ignore, T).
process_delete_file_opts([recursive|Opts], Dir, on, Ignore, T) :- !,
process_delete_file_opts(Opts, Dir, _, Ignore, T).
process_delete_file_opts([ignore|Opts], Dir, Recurse, on, T) :- !,
process_delete_file_opts(Opts, Dir, Recurse, _, T).
process_delete_file_opts(Opts, _, _, _, T) :-
throw(error(domain_error(delete_file_option,Opts),T)).
delete_file(IFile, Dir, Recurse, Ignore) :-
true_file_name(IFile, File),
file_property(File, Type, _, _, _Permissions, _, Ignore),
delete_file(Type, File, Dir, Recurse, Ignore).
delete_file(N, File, _Dir, _Recurse, Ignore) :- number(N), !, % error.
handle_system_error(N, Ignore, delete_file(File)).
delete_file(directory, File, Dir, Recurse, Ignore) :-
delete_directory(Dir, File, Recurse, Ignore).
delete_file(_, File, _Dir, _Recurse, Ignore) :-
unlink_file(File, Ignore).
unlink_file(IFile, Ignore) :-
true_file_name(IFile, File),
unlink(File, N),
handle_system_error(N, Ignore, delete_file(File)).
delete_directory(on, File, _Recurse, Ignore) :-
rm_directory(File, Ignore).
delete_directory(off, File, Recurse, Ignore) :-
delete_directory(Recurse, File, Ignore).
rm_directory(File, Ignore) :-
rmdir(File, Error),
handle_system_error(Error, Ignore, delete_file(File)).
delete_directory(on, File, Ignore) :-
directory_files(File, FileList, Ignore),
path_separator(D),
atom_concat(File, D, FileP),
delete_dirfiles(FileList, FileP, Ignore),
rmdir(File, Ignore).
delete_dirfiles([], _, _).
delete_dirfiles(['.'|Fs], File, Ignore) :- !,
delete_dirfiles(Fs, File, Ignore).
delete_dirfiles(['..'|Fs], File, Ignore) :- !,
delete_dirfiles(Fs, File, Ignore).
delete_dirfiles([F|Fs], File, Ignore) :-
atom_concat(File,F,TrueF),
delete_file(TrueF, off, on, Ignore),
delete_dirfiles(Fs, File, Ignore).
directory_files(IFile, FileList) :-
true_file_name(IFile, File),
directory_files(File, FileList, off).
directory_files(File, FileList, Ignore) :-
list_directory(File, FileList, Error),
handle_system_error(Error, Ignore, directory_files(File, FileList)).
handle_system_error(Error, _Ignore, _G) :- var(Error), !.
handle_system_error(Error, off, G) :- atom(Error), !,
@ -216,29 +143,6 @@ file_exists(IFile, Permissions) :-
process_permissions(Number, Number) :- integer(Number).
make_directory(Dir) :-
var(Dir), !,
throw(error(instantiation_error,mkdir(Dir))).
make_directory(IDir) :-
atom(IDir), !,
true_file_name(IDir, Dir),
mkdir(Dir,Error),
handle_system_error(Error, off, mkdir(IDir)).
make_directory(Dir) :-
throw(error(type_error(atom,Dir),make_directory(Dir))).
rename_file(IOld, New) :-
atom(IOld), atom(New), !,
true_file_name(IOld,Old),
rename_file(Old, New, Error),
handle_system_error(Error, off, rename_file(Old, New)).
rename_file(X,Y) :- (var(X) ; var(Y)), !,
throw(error(instantiation_error,rename_file(X,Y))).
rename_file(X,Y) :- atom(X), !,
throw(error(type_error(atom,Y),rename_file(X,Y))).
rename_file(X,Y) :-
throw(error(type_error(atom,X),rename_file(X,Y))).
%
% environment manipulation.
%
@ -413,18 +317,6 @@ system(Command, Status) :-
Status = 0,
handle_system_error(Error, off, G).
sleep(Interval) :- var(Interval), !,
throw(error(instantiation_error,sleep(Interval))).
sleep(Interval) :- number(Interval), !,
( Interval =< 0 ->
throw(error(domain_error(not_less_than_zero,Interval),
sleep(Interval)))
;
sleep(Interval, _Remainder)
).
sleep(Interval) :-
throw(error(type_error(number,Interval),sleep(Interval))).
wait(PID,STATUS) :- var(PID), !,
throw(error(instantiation_error,wait(PID,STATUS))).
wait(PID,STATUS) :- integer(PID), !,
@ -474,28 +366,6 @@ tmpnam(X) :-
tmpnam(X, Error),
handle_system_error(Error, off, tmpnam(X)).
tmp_file(Base,X) :-
var(Base), !,
throw(error(instantiation_error,tmp_file(Base,X))).
tmp_file(Base,X) :-
atom(Base), !,
tmpdir(Dir),
handle_system_error(Error, off, tmp_file(Base,X)),
pid(PID, Error),
handle_system_error(Error, off, tmp_file(Base,X)),
tmp_file_sequence(I),
% path_separator(D),
atomic_concat([Dir,yap_,Base,'_',PID,'_',I],X).
tmp_file(Base,X) :-
throw(error(type_error(atom,Base),tmp_file(Base,X))).
tmp_file_sequence(X) :-
retract(tmp_file_sequence_counter(X)),
X1 is X+1,
assert(tmp_file_sequence_counter(X1)).
tmp_file_sequence(0) :-
assert(tmp_file_sequence_counter(1)).
%%% Added from Theo, path_seperator is used to replace the c predicate dir_separator which is not OS aware
tmpdir(TmpDir):-

View File

@ -346,6 +346,7 @@ F Creep Creep 1
F Csult Csult 1
F CurrentModule CurrentModule 1
F CutBy CutBy 1
F DBREF DBREF 1
F Diff Diff 2
F DoLogUpdClause DoLogUpdClause 6
F DoLogUpdClause0 DoLogUpdClause0 6

View File

@ -174,8 +174,8 @@ struct worker worker WORKER void
#ifdef THREADS
struct thandle thread_handle ThreadHandle InitThreadHandle(wid)
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)].thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id].thread_handle)
#define FOREIGN_ThreadHandle(wid) (Yap_WLocal[(wid)]->thread_handle)
#define MY_ThreadHandle (Yap_WLocal[worker_id]->thread_handle)
#endif
// END WORKER LOCAL STUFF

View File

@ -46,13 +46,13 @@ HEADERS = \
$(srcdir)/CptEntry.h \
$(srcdir)/BifInterface.h \
$(srcdir)/xmlParser/xmlParser.h
CPP_SOURCES = \
$(srcdir)/BayesianNetwork.cpp \
$(srcdir)/BayesianNode.cpp \
$(srcdir)/BpNetwork.cpp \
$(srcdir)/BpNode.cpp \
$(srcdir)/Distribution.cpp \
$(srcdir)/Distribution.cpp \
$(srcdir)/CptEntry.cpp \
$(srcdir)/Horus.cpp \
$(srcdir)/BifInterface.cpp \

View File

@ -5,29 +5,41 @@
static inline Word
INIT_SEQ_STRING(size_t n)
{
return (Word)YAP_OpenList(n);
return RepPair(YAP_OpenList(n));
}
static inline Word
EXTEND_SEQ_CODES(Word gstore, int c) {
return (Word)YAP_ExtendList((YAP_Term)gstore, YAP_MkIntTerm(c));
EXTEND_SEQ_CODES(Word ptr, int c) {
ptr[0] = MkIntegerTerm(c);
ptr[1] = AbsPair(ptr+2);
return ptr+2;
}
static inline Word
EXTEND_SEQ_CHARS(Word gstore, int c) {
return (Word)YAP_ExtendList((YAP_Term)gstore, codeToAtom(c));
EXTEND_SEQ_CHARS(Word ptr, int c) {
ptr[0] = codeToAtom(c);
ptr[1] = AbsPair(ptr+2);
return ptr+2;
}
static inline int
CLOSE_SEQ_STRING(Word gstore, Word lp, word arg2, word arg3, term_t l) {
if (arg2 == 0) {
if (!YAP_CloseList((YAP_Term)gstore, YAP_TermNil()))
return FALSE;
CLOSE_SEQ_STRING(Word p, Word p0, term_t tail, term_t term, term_t l) {
CACHE_REGS
Yap_PutInSlot(l, AbsPair(p0) PASS_REGS);
p--;
if (tail) {
RESET_VARIABLE(p);
if (Yap_unify(Yap_GetFromSlot(l PASS_REGS), Yap_GetFromSlot(term PASS_REGS))) {
Yap_PutInSlot(tail, (CELL)(p) PASS_REGS);
return TRUE;
}
return FALSE;
} else {
if (!YAP_CloseList((YAP_Term)gstore, YAP_GetFromSlot(arg2)))
return FALSE;
p[0] = YAP_TermNil();
return Yap_unify(Yap_GetFromSlot(l PASS_REGS), Yap_GetFromSlot(term PASS_REGS));
}
return YAP_Unify(YAP_GetFromSlot(arg3), (YAP_Term)lp);
}
#endif

View File

@ -774,7 +774,7 @@ BeginPredDefs(ctype)
PRED_DEF("setlocale", 3, setlocale, 0)
PRED_DEF("downcase_atom", 2, downcase_atom, 0)
PRED_DEF("upcase_atom", 2, upcase_atom, 0)
PRED_DEF("swi_normalize_space", 2, normalize_space, 0)
PRED_DEF("normalize_space", 2, normalize_space, 0)
EndPredDefs

View File

@ -4672,6 +4672,18 @@ EndPredDefs
#if __YAP_PROLOG__
static word
pl_sleep(term_t time)
{ double t;
if ( PL_get_float_ex(time, &t) )
return Pause(t);
fail;
}
static const PL_extension foreigns[] = {
FRG("nl", 0, pl_nl, ISO),
FRG("write_canonical", 1, pl_write_canonical, ISO),
@ -4688,6 +4700,7 @@ static const PL_extension foreigns[] = {
FRG("print", 2, pl_print2, 0),
FRG("write_canonical", 2, pl_write_canonical2, ISO),
FRG("format", 3, pl_format3, META),
FRG("sleep", 1, pl_sleep, 0),
// vsc
FRG("format_predicate", 2, pl_format_predicate, META),
@ -4701,9 +4714,19 @@ static const PL_extension foreigns[] = {
struct PL_local_data *Yap_InitThreadIO(int wid)
{
struct PL_local_data *p = (struct PL_local_data *)calloc(sizeof(struct PL_local_data), 1);
CACHE_REGS
struct PL_local_data *p;
if (wid)
p = (struct PL_local_data *)malloc(sizeof(struct PL_local_data));
else
p = (struct PL_local_data *)calloc(sizeof(struct PL_local_data), 1);
if (!p) {
Yap_Error(OUT_OF_HEAP_ERROR, 0L, "Creating thread %d\n", wid);
return p;
}
if (wid) {
/* copy from other worker */
memcpy(p, Yap_WLocal[worker_id]->Yap_ld_, sizeof(struct PL_local_data));
}
return p;
}

View File

@ -342,6 +342,15 @@ setCurrentSourceLocation(IOSTREAM *s ARG_LD)
source_file_name = NULL_ATOM;
}
#if __YAP_PROLOG__
void
Yap_setCurrentSourceLocation(IOSTREAM *s)
{
GET_LD
setCurrentSourceLocation(s PASS_LD);
}
#endif
static inline int
getchr__(ReadData _PL_rd)

View File

@ -473,7 +473,6 @@ PL_unify_text(term_t term, term_t tail, PL_chars_t *text, int type)
return FALSE;
}
}
return CLOSE_SEQ_STRING(p, p0, tail, term, l );
}
}

View File

@ -698,6 +698,27 @@ PL_get_list_chars(term_t l, char **s, unsigned flags)
}
int
PL_unify_wchars_diff(term_t t, term_t tail, int flags,
size_t len, const pl_wchar_t *s)
{ PL_chars_t text;
int rc;
if ( len == (size_t)-1 )
len = wcslen(s);
text.text.w = (pl_wchar_t *)s;
text.encoding = ENC_WCHAR;
text.storage = PL_CHARS_HEAP;
text.length = len;
text.canonical = FALSE;
rc = PL_unify_text(t, tail, &text, flags);
PL_free_text(&text);
return rc;
}
int
PL_get_wchars(term_t l, size_t *length, pl_wchar_t **s, unsigned flags)
{ GET_LD
@ -1046,6 +1067,16 @@ recursiveMutexInit(recursiveMutex *m)
}
word
pl_sleep(term_t time)
{ double t;
if ( PL_get_float_ex(time, &t) )
return Pause(t);
fail;
}
counting_mutex _PL_mutexes[] =

View File

@ -114,7 +114,7 @@ void PL_license(const char *license, const char *module);
#define arityFunctor(f) YAP_PLArityOfSWIFunctor(f)
#define stringAtom(w) YAP_AtomName((YAP_Atom)(w))
#define isInteger(A) (YAP_IsIntTerm((A)) && YAP_IsBigNumTerm((A)))
#define isInteger(A) (YAP_IsIntTerm((A)) || YAP_IsBigNumTerm((A)))
#define isString(A) FALSE
#define isAtom(A) YAP_IsAtomTerm((A))
#define isList(A) YAP_IsPairTerm((A))

View File

@ -150,7 +150,7 @@ check-process::
( cd $(srcdir) && $(PL) -q -f test_process.pl -g true -t test_process )
check-read::
( cd $(srcdir) && $(PL) -q -f test_readutil.pl -g true -t test_readutilw )
( cd $(srcdir) && $(PL) -q -f test_readutil.pl -g true -t test_readutil )
################################################################
# Documentation

View File

@ -43,4 +43,7 @@
memory_file_to_codes/3, % +Handle, -CodeList, +Encoding
utf8_position_memory_file/3 % +Handle, -Here, -Size
]).
:- use_module(library(shlib)).
:- use_foreign_library(foreign(memfile)).

View File

@ -41,6 +41,7 @@
process_kill/2 % +PID, -Signal
]).
:- use_module(library(shlib)).
:- use_module(library(error)).
:- use_module(library(lists)).
:- use_module(library(option)).

View File

@ -37,6 +37,7 @@
stream_pool_main_loop/0
]).
:- use_module(library(quintus)).
:- use_module(library(debug)).
:- meta_predicate
add_stream_to_pool(+, :).

View File

@ -34,6 +34,8 @@
]).
:- asserta(user:file_search_path(foreign, '.')).
:- use_module(library(shlib)).
:- use_module(memfile).
:- use_module(library(utf8)).
@ -174,16 +176,16 @@ report_failed :-
runtest(Name) :-
format('Running test set "~w" ', [Name]),
flush,
flush_output,
functor(Head, Name, 1),
nth_clause(Head, _N, R),
clause(Head, _, R),
( catch(Head, Except, true)
-> ( var(Except)
-> put(.), flush
-> put(.), flush_output
; Except = blocked(Reason)
-> assert(blocked(Head, Reason)),
put(!), flush
put(!), flush_output
; test_failed(R, Except)
)
; test_failed(R, fail)

View File

@ -119,6 +119,8 @@ action(quit, _In, Out) :-
* CLIENT SIDE *
*******************************/
:- dynamic echo/1, slow/1, quit/1.
:- dynamic
client/2.
@ -182,7 +184,6 @@ reply(T, _, T).
receive_loop(Socket, Queue) :-
repeat,
writeln(hellorec),
udp_receive(Socket, Data, From, [as(atom)]),
thread_send_message(Queue, got(Data, From)),
Data == quit, !,
@ -211,9 +212,7 @@ run_udp :-
thread_get_message(got(X, _)),
udp_send(S, 'quit', localhost:Port, []),
thread_get_message(got(Q, _)),
writeln(hello2),
thread_join(ThreadId, Exit),
writeln(hello2),
tcp_close_socket(S),
assertion(X=='hello world'),
assertion(Q=='quit'),
@ -261,16 +260,16 @@ report_failed :-
runtest(Name) :-
format('Running test set "~w" ', [Name]),
flush,
flush_output,
functor(Head, Name, 1),
nth_clause(Head, _N, R),
clause(Head, _N, R),
clause(Head, _, R),
( catch(Head, Except, true)
-> ( var(Except)
-> put(.), flush
-> put(.), flush_output
; Except = blocked(Reason)
-> assert(blocked(Head, Reason)),
put(!), flush
put(!), flush_output
; test_failed(R, Except)
)
; test_failed(R, fail)

View File

@ -46,6 +46,9 @@
uri_file_name/2, % ?URI, ?Path
uri_iri/2 % ?URI, ?IRI
]).
:- use_module(library(shlib)).
:- use_foreign_library(foreign(uri)).
/** <module> Process URIs

View File

@ -381,14 +381,19 @@ true :- true.
'$nb_getval'('$if_skip_mode', skip, fail),
\+ '$if_directive'(Command),
!.
'$execute_command'((:-G),_,_,Option,_) :-
% !,
'$execute_command'((:-G),VL,Pos,Option,_) :-
% !,
Option \= top, !,
'$current_module'(M),
% allow user expansion
expand_term((:- G), O),
O = (:- G1),
'$process_directive'(G1, Option, M).
(
O = (:- G1)
->
'$process_directive'(G1, Option, M)
;
'$execute_commands'(O,VL,Pos,Option,O)
).
'$execute_command'((?-G), V, Pos, Option, Source) :-
Option \= top, !,
'$execute_command'(G, V, Pos, top, Source).

View File

@ -213,6 +213,8 @@ no_style_check([H|T]) :- no_style_check(H), no_style_check(T).
functor(Head, F, A),
'$is_multifile'(Head, M), !,
fail.
'$handle_discontiguous'((:-),1,_) :- !,
fail.
'$handle_discontiguous'(F,A,M) :-
nb_getval('$consulting_file', FileName),
% we have been there before

View File

@ -62,7 +62,7 @@ volatile(P) :-
% force backtracking and handling exceptions
fail.
'$close_thread'(Status, Detached) :-
'$close_thread'(Status, _Detached) :-
'$thread_zombie_self'(Id0), !,
'$record_thread_status'(Id0,Status),
'$run_at_thread_exit'(Id0),