disable stack shifting and garbage collection in the presence of
multiple threads. git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@646 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
parent
0351b9f0ab
commit
5a5c674300
@ -215,8 +215,6 @@ WakeAttVar(CELL* pt1, CELL reg2)
|
|||||||
Bind_Global(&(attv->Value), reg2);
|
Bind_Global(&(attv->Value), reg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mark_attvar(CELL *orig)
|
mark_attvar(CELL *orig)
|
||||||
{
|
{
|
||||||
@ -230,8 +228,6 @@ mark_attvar(CELL *orig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
|
|
||||||
#if FROZEN_STACKS
|
#if FROZEN_STACKS
|
||||||
static Term
|
static Term
|
||||||
CurrentTime(void) {
|
CurrentTime(void) {
|
||||||
@ -635,9 +631,7 @@ void InitAttVarPreds(void)
|
|||||||
attas[attvars_ext].copy_term_op = CopyAttVar;
|
attas[attvars_ext].copy_term_op = CopyAttVar;
|
||||||
attas[attvars_ext].to_term_op = AttVarToTerm;
|
attas[attvars_ext].to_term_op = AttVarToTerm;
|
||||||
attas[attvars_ext].term_to_op = TermToAttVar;
|
attas[attvars_ext].term_to_op = TermToAttVar;
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
attas[attvars_ext].mark_op = mark_attvar;
|
attas[attvars_ext].mark_op = mark_attvar;
|
||||||
#endif
|
|
||||||
InitCPred("get_att", 3, p_get_att, SafePredFlag);
|
InitCPred("get_att", 3, p_get_att, SafePredFlag);
|
||||||
InitCPred("get_all_atts", 2, p_get_all_atts, SafePredFlag);
|
InitCPred("get_all_atts", 2, p_get_all_atts, SafePredFlag);
|
||||||
InitCPred("free_att", 2, p_free_att, SafePredFlag);
|
InitCPred("free_att", 2, p_free_att, SafePredFlag);
|
||||||
|
@ -136,10 +136,8 @@ STATIC_PROTO(Int p_non_ground, (void));
|
|||||||
STATIC_PROTO(void Wake, (CELL *, CELL));
|
STATIC_PROTO(void Wake, (CELL *, CELL));
|
||||||
STATIC_PROTO(sus_record *UpdateSVarList, (sus_record *));
|
STATIC_PROTO(sus_record *UpdateSVarList, (sus_record *));
|
||||||
STATIC_PROTO(sus_record *GetSVarList, (void));
|
STATIC_PROTO(sus_record *GetSVarList, (void));
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
STATIC_PROTO(void mark_sus_record, (sus_record *));
|
STATIC_PROTO(void mark_sus_record, (sus_record *));
|
||||||
STATIC_PROTO(void mark_suspended_goal, (CELL *));
|
STATIC_PROTO(void mark_suspended_goal, (CELL *));
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
STATIC_PROTO(void AddSuspendedGoals, (sus_record *, sus_record *));
|
STATIC_PROTO(void AddSuspendedGoals, (sus_record *, sus_record *));
|
||||||
STATIC_PROTO(void ReleaseGoals, (sus_record *));
|
STATIC_PROTO(void ReleaseGoals, (sus_record *));
|
||||||
STATIC_PROTO(void wake_if_binding_vars_in_frozen_goal, (Term, sus_record *));
|
STATIC_PROTO(void wake_if_binding_vars_in_frozen_goal, (Term, sus_record *));
|
||||||
@ -394,8 +392,6 @@ TermToSuspendedVar(Term gs, Term var)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mark_sus_record(sus_record *sg)
|
mark_sus_record(sus_record *sg)
|
||||||
{
|
{
|
||||||
@ -420,8 +416,6 @@ static void mark_suspended_goal(CELL *orig)
|
|||||||
mark_external_reference(((CELL *)&(sreg->SG)));
|
mark_external_reference(((CELL *)&(sreg->SG)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -1211,9 +1205,7 @@ void InitCoroutPreds(void)
|
|||||||
attas[susp_ext].copy_term_op = CopySuspendedVar;
|
attas[susp_ext].copy_term_op = CopySuspendedVar;
|
||||||
attas[susp_ext].to_term_op = SuspendedVarToTerm;
|
attas[susp_ext].to_term_op = SuspendedVarToTerm;
|
||||||
attas[susp_ext].term_to_op = TermToSuspendedVar;
|
attas[susp_ext].term_to_op = TermToSuspendedVar;
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
attas[susp_ext].mark_op = mark_suspended_goal;
|
attas[susp_ext].mark_op = mark_suspended_goal;
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
at = LookupAtom("$wake_up_goal");
|
at = LookupAtom("$wake_up_goal");
|
||||||
pred = RepPredProp(PredPropByFunc(MkFunctor(at, 2),0));
|
pred = RepPredProp(PredPropByFunc(MkFunctor(at, 2),0));
|
||||||
WakeUpCode = pred;
|
WakeUpCode = pred;
|
||||||
|
35
C/grow.c
35
C/grow.c
@ -635,8 +635,11 @@ growheap(int fix_code)
|
|||||||
int shift_factor = (heap_overflows > 8 ? 8 : heap_overflows);
|
int shift_factor = (heap_overflows > 8 ? 8 : heap_overflows);
|
||||||
unsigned long sz = size << shift_factor;
|
unsigned long sz = size << shift_factor;
|
||||||
|
|
||||||
#ifdef FIXED_STACKS
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
abort_optyap("noheapleft in function absmi");
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot grow Heap: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (SizeOfOverflow > sz)
|
if (SizeOfOverflow > sz)
|
||||||
sz = AdjustPageSize(SizeOfOverflow);
|
sz = AdjustPageSize(SizeOfOverflow);
|
||||||
@ -674,8 +677,11 @@ growglobal(CELL **ptr)
|
|||||||
{
|
{
|
||||||
unsigned long sz = sizeof(CELL) * 16 * 1024L;
|
unsigned long sz = sizeof(CELL) * 16 * 1024L;
|
||||||
|
|
||||||
#ifdef FIXED_STACKS
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
abort_optyap("noheapleft in function absmi");
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot grow Global: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!local_growglobal(sz, ptr))
|
if (!local_growglobal(sz, ptr))
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@ -693,8 +699,11 @@ growstack(long size)
|
|||||||
Int start_growth_time, growth_time;
|
Int start_growth_time, growth_time;
|
||||||
int gc_verbose;
|
int gc_verbose;
|
||||||
|
|
||||||
#ifdef FIXED_STACKS
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
abort_optyap("nostackleft in function absmi");
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot grow Local: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* adjust to a multiple of 256) */
|
/* adjust to a multiple of 256) */
|
||||||
size = AdjustPageSize(size);
|
size = AdjustPageSize(size);
|
||||||
@ -812,8 +821,11 @@ growstack_in_parser(tr_fr_ptr *old_trp, TokEntry **tksp, VarEntry **vep)
|
|||||||
int gc_verbose;
|
int gc_verbose;
|
||||||
long size = sizeof(CELL)*(LCL0-(CELL *)GlobalBase);
|
long size = sizeof(CELL)*(LCL0-(CELL *)GlobalBase);
|
||||||
|
|
||||||
#ifdef FIXED_STACKS
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
abort_optyap("nostackleft in parser");
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot grow Parser Stack: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* adjust to a multiple of 256) */
|
/* adjust to a multiple of 256) */
|
||||||
size = AdjustPageSize(size);
|
size = AdjustPageSize(size);
|
||||||
@ -867,8 +879,11 @@ growtrail(long size)
|
|||||||
Int start_growth_time = cputime(), growth_time;
|
Int start_growth_time = cputime(), growth_time;
|
||||||
int gc_verbose = is_gc_verbose();
|
int gc_verbose = is_gc_verbose();
|
||||||
|
|
||||||
#ifdef FIXED_STACKS
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
abort_optyap("notrailleft in function absmi");
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot grow trail: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* adjust to a multiple of 256) */
|
/* adjust to a multiple of 256) */
|
||||||
size = AdjustPageSize(size);
|
size = AdjustPageSize(size);
|
||||||
|
16
C/heapgc.c
16
C/heapgc.c
@ -48,8 +48,6 @@ struct gc_ma_h_entry *live_list;
|
|||||||
STATIC_PROTO(Int p_inform_gc, (void));
|
STATIC_PROTO(Int p_inform_gc, (void));
|
||||||
STATIC_PROTO(Int p_gc, (void));
|
STATIC_PROTO(Int p_gc, (void));
|
||||||
|
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
|
|
||||||
#ifdef EASY_SHUNTING
|
#ifdef EASY_SHUNTING
|
||||||
static choiceptr current_B;
|
static choiceptr current_B;
|
||||||
|
|
||||||
@ -3100,8 +3098,6 @@ do_gc(Int predarity, CELL *current_env, yamop *nextop)
|
|||||||
return(effectiveness);
|
return(effectiveness);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
|
|
||||||
int
|
int
|
||||||
is_gc_verbose(void)
|
is_gc_verbose(void)
|
||||||
{
|
{
|
||||||
@ -3140,14 +3136,17 @@ p_inform_gc(void)
|
|||||||
int
|
int
|
||||||
gc(Int predarity, CELL *current_env, yamop *nextop)
|
gc(Int predarity, CELL *current_env, yamop *nextop)
|
||||||
{
|
{
|
||||||
#ifdef FIXED_STACKS
|
|
||||||
abort_optyap("garbage collection");
|
|
||||||
#else /* FIXED_STACKS */
|
|
||||||
Int gc_margin = 128;
|
Int gc_margin = 128;
|
||||||
Term Tgc_margin;
|
Term Tgc_margin;
|
||||||
Int effectiveness = 0;
|
Int effectiveness = 0;
|
||||||
int gc_on = FALSE;
|
int gc_on = FALSE;
|
||||||
|
|
||||||
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot perform garbage collection: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (GetValue(AtomGc) != TermNil)
|
if (GetValue(AtomGc) != TermNil)
|
||||||
gc_on = TRUE;
|
gc_on = TRUE;
|
||||||
if (IsIntTerm(Tgc_margin = GetValue(AtomGcMargin)))
|
if (IsIntTerm(Tgc_margin = GetValue(AtomGcMargin)))
|
||||||
@ -3186,7 +3185,6 @@ gc(Int predarity, CELL *current_env, yamop *nextop)
|
|||||||
* debug for(save_total=1; save_total<=N; ++save_total)
|
* debug for(save_total=1; save_total<=N; ++save_total)
|
||||||
* plwrite(XREGS[save_total],DebugPutc,0);
|
* plwrite(XREGS[save_total],DebugPutc,0);
|
||||||
*/
|
*/
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
return ( TRUE );
|
return ( TRUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3194,9 +3192,7 @@ gc(Int predarity, CELL *current_env, yamop *nextop)
|
|||||||
static Int
|
static Int
|
||||||
p_gc(void)
|
p_gc(void)
|
||||||
{
|
{
|
||||||
#ifndef FIXED_STACKS
|
|
||||||
do_gc(0, ENV, P);
|
do_gc(0, ENV, P);
|
||||||
#endif /* FIXED_STACKS */
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
C/init.c
1
C/init.c
@ -834,6 +834,7 @@ InitCodes(void)
|
|||||||
INIT_LOCK(heap_regs->heap_used_lock);
|
INIT_LOCK(heap_regs->heap_used_lock);
|
||||||
INIT_LOCK(heap_regs->heap_top_lock);
|
INIT_LOCK(heap_regs->heap_top_lock);
|
||||||
INIT_LOCK(heap_regs->dead_clauses_lock);
|
INIT_LOCK(heap_regs->dead_clauses_lock);
|
||||||
|
heap_regs->n_of_threads = 1;
|
||||||
heap_regs->heap_top_owner = -1;
|
heap_regs->heap_top_owner = -1;
|
||||||
#endif /* YAPOR */
|
#endif /* YAPOR */
|
||||||
heap_regs->clausecode.arity = 0;
|
heap_regs->clausecode.arity = 0;
|
||||||
|
12
C/save.c
12
C/save.c
@ -553,6 +553,10 @@ do_save(int mode) {
|
|||||||
static Int
|
static Int
|
||||||
p_save(void)
|
p_save(void)
|
||||||
{
|
{
|
||||||
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
which_save = 1;
|
which_save = 1;
|
||||||
return(do_save(DO_EVERYTHING));
|
return(do_save(DO_EVERYTHING));
|
||||||
}
|
}
|
||||||
@ -561,6 +565,10 @@ p_save(void)
|
|||||||
static Int
|
static Int
|
||||||
p_save2(void)
|
p_save2(void)
|
||||||
{
|
{
|
||||||
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
which_save = 2;
|
which_save = 2;
|
||||||
return(do_save(DO_EVERYTHING) && unify(ARG2,MkIntTerm(1)));
|
return(do_save(DO_EVERYTHING) && unify(ARG2,MkIntTerm(1)));
|
||||||
}
|
}
|
||||||
@ -1499,6 +1507,10 @@ p_restore(void)
|
|||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
Term t1 = Deref(ARG1);
|
Term t1 = Deref(ARG1);
|
||||||
|
if (NOfThreads != 1) {
|
||||||
|
Error(SYSTEM_ERROR,TermNil,"cannot perform save: more than a worker/thread running");
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
if (!GetName(FileNameBuf, YAP_FILENAME_MAX, t1)) {
|
if (!GetName(FileNameBuf, YAP_FILENAME_MAX, t1)) {
|
||||||
Error(TYPE_ERROR_LIST,t1,"restore/1");
|
Error(TYPE_ERROR_LIST,t1,"restore/1");
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
|
@ -1010,7 +1010,7 @@ SearchForTrailFault(void)
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* fprintf(stderr,"Catching a sigsegv at %p with %p\n", TR, TrailTop); */
|
/* fprintf(stderr,"Catching a sigsegv at %p with %p\n", TR, TrailTop); */
|
||||||
#endif
|
#endif
|
||||||
#ifndef FIXED_STACKS
|
#if !OS_HANDLES_TR_OVERFLOW
|
||||||
if ((TR > (tr_fr_ptr)TrailTop-1024 &&
|
if ((TR > (tr_fr_ptr)TrailTop-1024 &&
|
||||||
TR < (tr_fr_ptr)TrailTop+(64*1024))|| DBTrailOverflow()) {
|
TR < (tr_fr_ptr)TrailTop+(64*1024))|| DBTrailOverflow()) {
|
||||||
if (!growtrail(64 * 1024L)) {
|
if (!growtrail(64 * 1024L)) {
|
||||||
@ -1019,7 +1019,7 @@ SearchForTrailFault(void)
|
|||||||
/* just in case, make sure the OS keeps the signal handler. */
|
/* just in case, make sure the OS keeps the signal handler. */
|
||||||
/* my_signal_info(SIGSEGV, HandleSIGSEGV); */
|
/* my_signal_info(SIGSEGV, HandleSIGSEGV); */
|
||||||
} else
|
} else
|
||||||
#endif /* FIXED_STACKS */
|
#endif /* OS_HANDLES_TR_OVERFLOW */
|
||||||
Error(FATAL_ERROR, TermNil,
|
Error(FATAL_ERROR, TermNil,
|
||||||
"likely bug in YAP, segmentation violation");
|
"likely bug in YAP, segmentation violation");
|
||||||
}
|
}
|
||||||
|
12
H/Heap.h
12
H/Heap.h
@ -10,7 +10,7 @@
|
|||||||
* File: Heap.h *
|
* File: Heap.h *
|
||||||
* mods: *
|
* mods: *
|
||||||
* comments: Heap Init Structure *
|
* comments: Heap Init Structure *
|
||||||
* version: $Id: Heap.h,v 1.32 2002-10-14 16:25:33 vsc Exp $ *
|
* version: $Id: Heap.h,v 1.33 2002-10-21 22:52:36 vsc Exp $ *
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
|
||||||
/* information that can be stored in Code Space */
|
/* information that can be stored in Code Space */
|
||||||
@ -128,9 +128,6 @@ typedef struct various_codes {
|
|||||||
Int maxdepth, maxlist;
|
Int maxdepth, maxlist;
|
||||||
int update_mode;
|
int update_mode;
|
||||||
Atom atprompt;
|
Atom atprompt;
|
||||||
#if defined(YAPOR) || defined(THREADS)
|
|
||||||
lockvar heap_used_lock; /* protect HeapUsed */
|
|
||||||
#endif
|
|
||||||
char prompt[MAX_PROMPT];
|
char prompt[MAX_PROMPT];
|
||||||
OPCODE undef_op;
|
OPCODE undef_op;
|
||||||
OPCODE index_op;
|
OPCODE index_op;
|
||||||
@ -149,8 +146,11 @@ typedef struct various_codes {
|
|||||||
char *char_conversion_table;
|
char *char_conversion_table;
|
||||||
char *char_conversion_table2;
|
char *char_conversion_table2;
|
||||||
#if defined(YAPOR) || defined(THREADS)
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
|
lockvar heap_used_lock; /* protect HeapUsed */
|
||||||
lockvar heap_top_lock; /* protect HeapTop */
|
lockvar heap_top_lock; /* protect HeapTop */
|
||||||
|
lockvar dead_clauses_lock; /* protect DeadClauses */
|
||||||
int heap_top_owner;
|
int heap_top_owner;
|
||||||
|
unsigned int n_of_threads; /* number of threads and processes in system */
|
||||||
#endif
|
#endif
|
||||||
unsigned int size_of_overflow;
|
unsigned int size_of_overflow;
|
||||||
UInt number_of_cpreds;
|
UInt number_of_cpreds;
|
||||||
@ -159,9 +159,6 @@ typedef struct various_codes {
|
|||||||
struct pred_entry *module_pred[MaxModules];
|
struct pred_entry *module_pred[MaxModules];
|
||||||
SMALLUNSGN no_of_modules;
|
SMALLUNSGN no_of_modules;
|
||||||
struct clause_struct *dead_clauses;
|
struct clause_struct *dead_clauses;
|
||||||
#if defined(YAPOR) || defined(THREADS)
|
|
||||||
lockvar dead_clauses_lock; /* protect DeadClauses */
|
|
||||||
#endif
|
|
||||||
int primitives_module;
|
int primitives_module;
|
||||||
int user_module;
|
int user_module;
|
||||||
struct idb_queue *db_queues, *db_queues_cache;
|
struct idb_queue *db_queues, *db_queues_cache;
|
||||||
@ -520,6 +517,7 @@ typedef struct various_codes {
|
|||||||
#define FreeBlocksLock heap_regs->free_blocks_lock
|
#define FreeBlocksLock heap_regs->free_blocks_lock
|
||||||
#define HeapTopLock heap_regs->heap_top_lock
|
#define HeapTopLock heap_regs->heap_top_lock
|
||||||
#define HeapTopOwner heap_regs->heap_top_owner
|
#define HeapTopOwner heap_regs->heap_top_owner
|
||||||
|
#define NOfThreads heap_regs->n_of_threads
|
||||||
#define HeapUsedLock heap_regs->heap_used_lock
|
#define HeapUsedLock heap_regs->heap_used_lock
|
||||||
#define DeadClausesLock heap_regs->dead_clauses_lock
|
#define DeadClausesLock heap_regs->dead_clauses_lock
|
||||||
#endif
|
#endif
|
||||||
|
@ -674,7 +674,7 @@ Macros to check the limits of stacks
|
|||||||
/* for the moment I don't know how to handle trail overflows
|
/* for the moment I don't know how to handle trail overflows
|
||||||
in a pure Windows environment
|
in a pure Windows environment
|
||||||
*/
|
*/
|
||||||
#if !_MSC_VER && !defined(__MINGW32__)
|
#if !_MSC_VER && !defined(__MINGW32__) && !defined(THREADS) && !defined(YAPOR)
|
||||||
#define OS_HANDLES_TR_OVERFLOW 1
|
#define OS_HANDLES_TR_OVERFLOW 1
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -229,6 +229,7 @@ void make_root_frames(void) {
|
|||||||
#ifdef YAPOR
|
#ifdef YAPOR
|
||||||
void init_workers(void) {
|
void init_workers(void) {
|
||||||
int proc;
|
int proc;
|
||||||
|
NOfThreads = number_workers;
|
||||||
#ifdef ACOW
|
#ifdef ACOW
|
||||||
if (number_workers > 1) {
|
if (number_workers > 1) {
|
||||||
int son;
|
int son;
|
||||||
|
Reference in New Issue
Block a user