FORM  4.2
threads.c
Go to the documentation of this file.
1 
22 /* #[ License : */
23 /*
24  * Copyright (C) 1984-2017 J.A.M. Vermaseren
25  * When using this file you are requested to refer to the publication
26  * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
27  * This is considered a matter of courtesy as the development was paid
28  * for by FOM the Dutch physics granting agency and we would like to
29  * be able to track its scientific use to convince FOM of its value
30  * for the community.
31  *
32  * This file is part of FORM.
33  *
34  * FORM is free software: you can redistribute it and/or modify it under the
35  * terms of the GNU General Public License as published by the Free Software
36  * Foundation, either version 3 of the License, or (at your option) any later
37  * version.
38  *
39  * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
40  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
41  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
42  * details.
43  *
44  * You should have received a copy of the GNU General Public License along
45  * with FORM. If not, see <http://www.gnu.org/licenses/>.
46  */
47 /* #] License : */
48 
49 #ifdef WITHPTHREADS
50 
51 #define WHOLEBRACKETS
52 /*
53  #[ Variables :
54 
55  The sortbot additions are from 17-may-2007 and after. They consitute
56  an attempt to make the final merge sorting faster for the master.
57  This way the master has only one compare per term.
58  It does add some complexity, but the final merge routine (MasterMerge)
59  is much simpler for the sortbots. On the other hand the original merging is
60  for a large part a copy of the MergePatches routine in sort.c and hence
61  even though complex the bad part has been thoroughly debugged.
62 */
63 
64 #include "form3.h"
65 
66 static int numberofthreads;
67 static int numberofworkers;
68 static int identityofthreads = 0;
69 static int *listofavailables;
70 static int topofavailables = 0;
71 static pthread_key_t identitykey;
72 static INILOCK(numberofthreadslock);
73 static INILOCK(availabilitylock);
74 static pthread_t *threadpointers = 0;
75 static pthread_mutex_t *wakeuplocks;
76 static pthread_mutex_t *wakeupmasterthreadlocks;
77 static pthread_cond_t *wakeupconditions;
78 static pthread_condattr_t *wakeupconditionattributes;
79 static int *wakeup;
80 static int *wakeupmasterthread;
81 static INILOCK(wakeupmasterlock);
82 static pthread_cond_t wakeupmasterconditions = PTHREAD_COND_INITIALIZER;
83 static pthread_cond_t *wakeupmasterthreadconditions;
84 static int wakeupmaster = 0;
85 static int identityretval;
86 /* static INILOCK(clearclocklock); */
87 static LONG *timerinfo;
88 static LONG *sumtimerinfo;
89 static int numberclaimed;
90 
91 static THREADBUCKET **threadbuckets, **freebuckets;
92 static int numthreadbuckets;
93 static int numberoffullbuckets;
94 
95 /* static int numberbusy = 0; */
96 
97 INILOCK(dummylock);
98 INIRWLOCK(dummyrwlock);
99 static pthread_cond_t dummywakeupcondition = PTHREAD_COND_INITIALIZER;
100 
101 #ifdef WITHSORTBOTS
102 static POSITION SortBotPosition;
103 static int numberofsortbots;
104 static INILOCK(wakeupsortbotlock);
105 static pthread_cond_t wakeupsortbotconditions = PTHREAD_COND_INITIALIZER;
106 static int topsortbotavailables = 0;
107 static LONG numberofterms;
108 #endif
109 
110 /*
111  #] Variables :
112  #[ Identity :
113  #[ StartIdentity :
114 */
120 void StartIdentity()
121 {
122  pthread_key_create(&identitykey,FinishIdentity);
123 }
124 
125 /*
126  #] StartIdentity :
127  #[ FinishIdentity :
128 */
133 void FinishIdentity(void *keyp)
134 {
135  DUMMYUSE(keyp);
136 /* free(keyp); */
137 }
138 
139 /*
140  #] FinishIdentity :
141  #[ SetIdentity :
142 */
147 int SetIdentity(int *identityretval)
148 {
149 /*
150 #ifdef _MSC_VER
151  printf("addr %d\n",&numberofthreadslock);
152  printf("size %d\n",sizeof(numberofthreadslock));
153 #endif
154 */
155  LOCK(numberofthreadslock);
156  *identityretval = identityofthreads++;
157  UNLOCK(numberofthreadslock);
158  pthread_setspecific(identitykey,(void *)identityretval);
159  return(*identityretval);
160 }
161 
162 /*
163  #] SetIdentity :
164  #[ WhoAmI :
165 */
166 
177 int WhoAmI()
178 {
179  int *identity;
180 /*
181  First a fast exit for when there is at most one thread
182 */
183  if ( identityofthreads <= 1 ) return(0);
184 /*
185  Now the reading of the key.
186  According to the book the statement should read:
187 
188  pthread_getspecific(identitykey,(void **)(&identity));
189 
190  but according to the information in pthread.h it is:
191 */
192  identity = (int *)pthread_getspecific(identitykey);
193  return(*identity);
194 }
195 
196 /*
197  #] WhoAmI :
198  #[ BeginIdentities :
199 */
205 VOID BeginIdentities()
206 {
207  StartIdentity();
208  SetIdentity(&identityretval);
209 }
210 
211 /*
212  #] BeginIdentities :
213  #] Identity :
214  #[ StartHandleLock :
215 */
222 void StartHandleLock()
223 {
224  AM.handlelock = dummyrwlock;
225 }
226 
227 /*
228  #] StartHandleLock :
229  #[ StartAllThreads :
230 */
248 int StartAllThreads(int number)
249 {
250  int identity, j, dummy, mul;
251  ALLPRIVATES *B;
252  pthread_t thethread;
253  identity = WhoAmI();
254 
255 #ifdef WITHSORTBOTS
256  timerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"timerinfo");
257  sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"sumtimerinfo");
258  for ( j = 0; j < number*2; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
259  mul = 2;
260 #else
261  timerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"timerinfo");
262  sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"sumtimerinfo");
263  for ( j = 0; j < number; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
264  mul = 1;
265 #endif
266 
267  listofavailables = (int *)Malloc1(sizeof(int)*(number+1),"listofavailables");
268  threadpointers = (pthread_t *)Malloc1(sizeof(pthread_t)*number*mul,"threadpointers");
269  AB = (ALLPRIVATES **)Malloc1(sizeof(ALLPRIVATES *)*number*mul,"Private structs");
270 
271  wakeup = (int *)Malloc1(sizeof(int)*number*mul,"wakeup");
272  wakeuplocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeuplocks");
273  wakeupconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupconditions");
274  wakeupconditionattributes = (pthread_condattr_t *)
275  Malloc1(sizeof(pthread_condattr_t)*number*mul,"wakeupconditionattributes");
276 
277  wakeupmasterthread = (int *)Malloc1(sizeof(int)*number*mul,"wakeupmasterthread");
278  wakeupmasterthreadlocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeupmasterthreadlocks");
279  wakeupmasterthreadconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupmasterthread");
280 
281  numberofthreads = number;
282  numberofworkers = number - 1;
283  threadpointers[identity] = pthread_self();
284  topofavailables = 0;
285  for ( j = 1; j < number; j++ ) {
286  if ( pthread_create(&thethread,NULL,RunThread,(void *)(&dummy)) )
287  goto failure;
288  }
289 /*
290  Now we initialize the master at the same time that the workers are doing so.
291 */
292  B = InitializeOneThread(identity);
293  AR.infile = &(AR.Fscr[0]);
294  AR.outfile = &(AR.Fscr[1]);
295  AR.hidefile = &(AR.Fscr[2]);
296  AM.sbuflock = dummylock;
297  AS.inputslock = dummylock;
298  AS.outputslock = dummylock;
299  AS.MaxExprSizeLock = dummylock;
300  AP.PreVarLock = dummylock;
301  AC.halfmodlock = dummylock;
302  MakeThreadBuckets(number,0);
303 /*
304  Now we wait for the workers to finish their startup.
305  We don't want to initialize the sortbots yet and run the risk that
306  some of them may end up with a lower number than one of the workers.
307 */
308  MasterWaitAll();
309 #ifdef WITHSORTBOTS
310  if ( numberofworkers > 2 ) {
311  numberofsortbots = numberofworkers-2;
312  for ( j = numberofworkers+1; j < 2*numberofworkers-1; j++ ) {
313  if ( pthread_create(&thethread,NULL,RunSortBot,(void *)(&dummy)) )
314  goto failure;
315  }
316  }
317  else {
318  numberofsortbots = 0;
319  }
320  MasterWaitAllSortBots();
321  DefineSortBotTree();
322 #endif
323  IniSortBlocks(number-1);
324  AS.MasterSort = 0;
325  AM.storefilelock = dummylock;
326 /*
327 MesPrint("AB = %x %x %x %d",AB[0],AB[1],AB[2], identityofthreads);
328 */
329  return(0);
330 failure:
331  MesPrint("Cannot start %d threads",number);
332  Terminate(-1);
333  return(-1);
334 }
335 
336 /*
337  #] StartAllThreads :
338  #[ InitializeOneThread :
339 */
343 UBYTE *scratchname[] = { (UBYTE *)"scratchsize",
344  (UBYTE *)"scratchsize",
345  (UBYTE *)"hidesize" };
372 ALLPRIVATES *InitializeOneThread(int identity)
373 {
374  WORD *t, *ScratchBuf;
375  int i, j, bsize, *bp;
376  LONG ScratchSize[3], IOsize;
377  ALLPRIVATES *B;
378  UBYTE *s;
379 
380  wakeup[identity] = 0;
381  wakeuplocks[identity] = dummylock;
382  pthread_condattr_init(&(wakeupconditionattributes[identity]));
383  pthread_condattr_setpshared(&(wakeupconditionattributes[identity]),PTHREAD_PROCESS_PRIVATE);
384  wakeupconditions[identity] = dummywakeupcondition;
385  pthread_cond_init(&(wakeupconditions[identity]),&(wakeupconditionattributes[identity]));
386  wakeupmasterthread[identity] = 0;
387  wakeupmasterthreadlocks[identity] = dummylock;
388  wakeupmasterthreadconditions[identity] = dummywakeupcondition;
389 
390  bsize = sizeof(ALLPRIVATES);
391  bsize = (bsize+sizeof(int)-1)/sizeof(int);
392  B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
393  for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
394 
395  AB[identity] = B;
396 /*
397  12-jun-2007 JV:
398  For the timing one has to know a few things:
399  The POSIX standard is that there is only a single process ID and that
400  getrusage returns the time of all the threads together.
401  Under Linux there are two methods though: The older LinuxThreads and NPTL.
402  LinuxThreads gives each thread its own process id. This makes that we
403  can time the threads with getrusage, and hence this was done. Under NPTL
404  this has been 'corrected' and suddenly getruage doesn't work anymore the
405  way it used to. Now we need
406  clock_gettime(CLOCK_THREAD_CPUTIME_ID,&timing)
407  which is declared in <time.h> and we need -lrt extra in the link statement.
408  (this is at least the case on blade02 at DESY-Zeuthen).
409  See also the code in tools.c at the routine Timer.
410  We may still have to include more stuff there.
411 */
412  if ( identity > 0 ) TimeCPU(0);
413 
414 #ifdef WITHSORTBOTS
415 
416  if ( identity > numberofworkers ) {
417 /*
418  Some workspace is needed when we have a PolyFun and we have to add
419  two terms and the new result is going to be longer than the old result.
420 */
421  LONG length = AM.WorkSize*sizeof(WORD)/8+AM.MaxTer*2;
422  AT.WorkSpace = (WORD *)Malloc1(length,"WorkSpace");
423  AT.WorkTop = AT.WorkSpace + length/sizeof(WORD);
424  AT.WorkPointer = AT.WorkSpace;
425  AT.identity = identity;
426 /*
427  The SB struct gets treated in IniSortBlocks.
428  The SortBotIn variables will be defined DefineSortBotTree.
429 */
430  if ( AN.SoScratC == 0 ) {
431  AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
432  }
433  AT.SS = (SORTING *)Malloc1(sizeof(SORTING),"dummy sort buffer");
434  AT.SS->PolyFlag = 0;
435 
436  AT.comsym[0] = 8;
437  AT.comsym[1] = SYMBOL;
438  AT.comsym[2] = 4;
439  AT.comsym[3] = 0;
440  AT.comsym[4] = 1;
441  AT.comsym[5] = 1;
442  AT.comsym[6] = 1;
443  AT.comsym[7] = 3;
444  AT.comnum[0] = 4;
445  AT.comnum[1] = 1;
446  AT.comnum[2] = 1;
447  AT.comnum[3] = 3;
448  AT.comfun[0] = FUNHEAD+4;
449  AT.comfun[1] = FUNCTION;
450  AT.comfun[2] = FUNHEAD;
451  AT.comfun[3] = 0;
452 #if FUNHEAD > 3
453  for ( i = 4; i <= FUNHEAD; i++ )
454  AT.comfun[i] = 0;
455 #endif
456  AT.comfun[FUNHEAD+1] = 1;
457  AT.comfun[FUNHEAD+2] = 1;
458  AT.comfun[FUNHEAD+3] = 3;
459  AT.comind[0] = 7;
460  AT.comind[1] = INDEX;
461  AT.comind[2] = 3;
462  AT.comind[3] = 0;
463  AT.comind[4] = 1;
464  AT.comind[5] = 1;
465  AT.comind[6] = 3;
466 
467  AT.inprimelist = -1;
468  AT.sizeprimelist = 0;
469  AT.primelist = 0;
470  AT.bracketinfo = 0;
471 
472  AR.CompareRoutine = &Compare1;
473 
474  AR.sLevel = 0;
475  AR.wranfia = 0;
476  AR.wranfcall = 0;
477  AR.wranfnpair1 = NPAIR1;
478  AR.wranfnpair2 = NPAIR2;
479  AN.NumFunSorts = 5;
480  AN.MaxFunSorts = 5;
481  AN.SplitScratch = 0;
482  AN.SplitScratchSize = AN.InScratch = 0;
483  AN.SplitScratch1 = 0;
484  AN.SplitScratchSize1 = AN.InScratch1 = 0;
485 
486  AN.FunSorts = (SORTING **)Malloc1((AN.NumFunSorts+1)*sizeof(SORTING *),"FunSort pointers");
487  for ( i = 0; i <= AN.NumFunSorts; i++ ) AN.FunSorts[i] = 0;
488  AN.FunSorts[0] = AT.S0 = AT.SS;
489  AN.idfunctionflag = 0;
490  AN.tryterm = 0;
491 
492  return(B);
493  }
494  if ( identity == 0 && AN.SoScratC == 0 ) {
495  AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
496  }
497 #endif
498  AR.CurDum = AM.IndDum;
499  for ( j = 0; j < 3; j++ ) {
500  if ( identity == 0 ) {
501  if ( j == 2 ) {
502  ScratchSize[j] = AM.HideSize;
503  }
504  else {
505  ScratchSize[j] = AM.ScratSize;
506  }
507  if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
508  }
509  else {
510 /*
511  ScratchSize[j] = AM.ScratSize / (numberofthreads-1);
512  ScratchSize[j] = ScratchSize[j] / 20;
513  if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
514 */
515  if ( j == 1 ) ScratchSize[j] = AM.ThreadScratOutSize;
516  else ScratchSize[j] = AM.ThreadScratSize;
517  if ( ScratchSize[j] < 4*AM.MaxTer ) ScratchSize[j] = 4 * AM.MaxTer;
518  AR.Fscr[j].name = 0;
519  }
520  ScratchSize[j] = ( ScratchSize[j] + 255 ) / 256;
521  ScratchSize[j] = ScratchSize[j] * 256;
522  ScratchBuf = (WORD *)Malloc1(ScratchSize[j]*sizeof(WORD),(char *)(scratchname[j]));
523  AR.Fscr[j].POsize = ScratchSize[j] * sizeof(WORD);
524  AR.Fscr[j].POfull = AR.Fscr[j].POfill = AR.Fscr[j].PObuffer = ScratchBuf;
525  AR.Fscr[j].POstop = AR.Fscr[j].PObuffer + ScratchSize[j];
526  PUTZERO(AR.Fscr[j].POposition);
527  AR.Fscr[j].pthreadslock = dummylock;
528  AR.Fscr[j].wPOsize = AR.Fscr[j].POsize;
529  AR.Fscr[j].wPObuffer = AR.Fscr[j].PObuffer;
530  AR.Fscr[j].wPOfill = AR.Fscr[j].POfill;
531  AR.Fscr[j].wPOfull = AR.Fscr[j].POfull;
532  AR.Fscr[j].wPOstop = AR.Fscr[j].POstop;
533  }
534  AR.InInBuf = 0;
535  AR.InHiBuf = 0;
536  AR.Fscr[0].handle = -1;
537  AR.Fscr[1].handle = -1;
538  AR.Fscr[2].handle = -1;
539  AR.FoStage4[0].handle = -1;
540  AR.FoStage4[1].handle = -1;
541  IOsize = AM.S0->file.POsize;
542 #ifdef WITHZLIB
543  AR.FoStage4[0].ziosize = IOsize;
544  AR.FoStage4[1].ziosize = IOsize;
545 #endif
546  AR.FoStage4[0].POsize = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
547  AR.FoStage4[1].POsize = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
548 
549  AR.hidefile = &(AR.Fscr[2]);
550  AR.StoreData.Handle = -1;
551  AR.SortType = AC.SortType;
552 
553  AN.IndDum = AM.IndDum;
554 
555  if ( identity > 0 ) {
556  s = (UBYTE *)(FG.fname); i = 0;
557  while ( *s ) { s++; i++; }
558  s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[0] file");
559  sprintf((char *)s,"%s.%d",FG.fname,identity);
560  s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '0';
561  AR.Fscr[0].name = (char *)s;
562  s = (UBYTE *)(FG.fname); i = 0;
563  while ( *s ) { s++; i++; }
564  s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[1] file");
565  sprintf((char *)s,"%s.%d",FG.fname,identity);
566  s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '1';
567  AR.Fscr[1].name = (char *)s;
568  }
569 
570  AR.CompressBuffer = (WORD *)Malloc1((AM.CompressSize+10)*sizeof(WORD),"compresssize");
571  AR.ComprTop = AR.CompressBuffer + AM.CompressSize;
572  AR.CompareRoutine = &Compare1;
573 /*
574  Here we make all allocations for the struct AT
575  (which is AB[identity].T or B->T with B = AB+identity).
576 */
577  AT.WorkSpace = (WORD *)Malloc1(AM.WorkSize*sizeof(WORD),"WorkSpace");
578  AT.WorkTop = AT.WorkSpace + AM.WorkSize;
579  AT.WorkPointer = AT.WorkSpace;
580 
581  AT.Nest = (NESTING)Malloc1((LONG)sizeof(struct NeStInG)*AM.maxFlevels,"functionlevels");
582  AT.NestStop = AT.Nest + AM.maxFlevels;
583  AT.NestPoin = AT.Nest;
584 
585  AT.WildMask = (WORD *)Malloc1((LONG)AM.MaxWildcards*sizeof(WORD),"maxwildcards");
586 
587  LOCK(availabilitylock);
588  AT.ebufnum = inicbufs(); /* Buffer for extras during execution */
589  AT.fbufnum = inicbufs(); /* Buffer for caching in factorization */
590  AT.allbufnum = inicbufs(); /* Buffer for id,all */
591  AT.aebufnum = inicbufs(); /* Buffer for id,all */
592  UNLOCK(availabilitylock);
593 
594  AT.RepCount = (int *)Malloc1((LONG)((AM.RepMax+3)*sizeof(int)),"repeat buffers");
595  AN.RepPoint = AT.RepCount;
596  AN.polysortflag = 0;
597  AN.subsubveto = 0;
598  AN.tryterm = 0;
599  AT.RepTop = AT.RepCount + AM.RepMax;
600 
601  AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
602  ,"argument list names");
603  AT.WildcardBufferSize = AC.WildcardBufferSize;
604  AT.previousEfactor = 0;
605 
606  AT.identity = identity;
607  AT.LoadBalancing = 0;
608 /*
609  Still to do: the SS stuff.
610  the Fscr[3]
611  the FoStage4[2]
612 */
613  if ( AT.WorkSpace == 0 ||
614  AT.Nest == 0 ||
615  AT.WildMask == 0 ||
616  AT.RepCount == 0 ||
617  AT.WildArgTaken == 0 ) goto OnError;
618 /*
619  And initializations
620 */
621  AT.comsym[0] = 8;
622  AT.comsym[1] = SYMBOL;
623  AT.comsym[2] = 4;
624  AT.comsym[3] = 0;
625  AT.comsym[4] = 1;
626  AT.comsym[5] = 1;
627  AT.comsym[6] = 1;
628  AT.comsym[7] = 3;
629  AT.comnum[0] = 4;
630  AT.comnum[1] = 1;
631  AT.comnum[2] = 1;
632  AT.comnum[3] = 3;
633  AT.comfun[0] = FUNHEAD+4;
634  AT.comfun[1] = FUNCTION;
635  AT.comfun[2] = FUNHEAD;
636  AT.comfun[3] = 0;
637 #if FUNHEAD > 3
638  for ( i = 4; i <= FUNHEAD; i++ )
639  AT.comfun[i] = 0;
640 #endif
641  AT.comfun[FUNHEAD+1] = 1;
642  AT.comfun[FUNHEAD+2] = 1;
643  AT.comfun[FUNHEAD+3] = 3;
644  AT.comind[0] = 7;
645  AT.comind[1] = INDEX;
646  AT.comind[2] = 3;
647  AT.comind[3] = 0;
648  AT.comind[4] = 1;
649  AT.comind[5] = 1;
650  AT.comind[6] = 3;
651  AT.locwildvalue[0] = SUBEXPRESSION;
652  AT.locwildvalue[1] = SUBEXPSIZE;
653  for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
654  AT.mulpat[0] = TYPEMULT;
655  AT.mulpat[1] = SUBEXPSIZE+3;
656  AT.mulpat[2] = 0;
657  AT.mulpat[3] = SUBEXPRESSION;
658  AT.mulpat[4] = SUBEXPSIZE;
659  AT.mulpat[5] = 0;
660  AT.mulpat[6] = 1;
661  for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
662  AT.proexp[0] = SUBEXPSIZE+4;
663  AT.proexp[1] = EXPRESSION;
664  AT.proexp[2] = SUBEXPSIZE;
665  AT.proexp[3] = -1;
666  AT.proexp[4] = 1;
667  for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
668  AT.proexp[SUBEXPSIZE+1] = 1;
669  AT.proexp[SUBEXPSIZE+2] = 1;
670  AT.proexp[SUBEXPSIZE+3] = 3;
671  AT.proexp[SUBEXPSIZE+4] = 0;
672  AT.dummysubexp[0] = SUBEXPRESSION;
673  AT.dummysubexp[1] = SUBEXPSIZE+4;
674  for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
675  AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
676  AT.dummysubexp[SUBEXPSIZE+1] = 4;
677  AT.dummysubexp[SUBEXPSIZE+2] = 0;
678  AT.dummysubexp[SUBEXPSIZE+3] = 0;
679 
680  AT.MinVecArg[0] = 7+ARGHEAD;
681  AT.MinVecArg[ARGHEAD] = 7;
682  AT.MinVecArg[1+ARGHEAD] = INDEX;
683  AT.MinVecArg[2+ARGHEAD] = 3;
684  AT.MinVecArg[3+ARGHEAD] = 0;
685  AT.MinVecArg[4+ARGHEAD] = 1;
686  AT.MinVecArg[5+ARGHEAD] = 1;
687  AT.MinVecArg[6+ARGHEAD] = -3;
688  t = AT.FunArg;
689  *t++ = 4+ARGHEAD+FUNHEAD;
690  for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
691  *t++ = 4+FUNHEAD;
692  *t++ = 0;
693  *t++ = FUNHEAD;
694  for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
695  *t++ = 1; *t++ = 1; *t++ = 3;
696 
697  AT.inprimelist = -1;
698  AT.sizeprimelist = 0;
699  AT.primelist = 0;
700  AT.nfac = AT.nBer = 0;
701  AT.factorials = 0;
702  AT.bernoullis = 0;
703  AR.wranfia = 0;
704  AR.wranfcall = 0;
705  AR.wranfnpair1 = NPAIR1;
706  AR.wranfnpair2 = NPAIR2;
707  AR.wranfseed = 0;
708  AN.SplitScratch = 0;
709  AN.SplitScratchSize = AN.InScratch = 0;
710  AN.SplitScratch1 = 0;
711  AN.SplitScratchSize1 = AN.InScratch1 = 0;
712 /*
713  Now the sort buffers. They depend on which thread. The master
714  inherits the sortbuffer from AM.S0
715 */
716  if ( identity == 0 ) {
717  AT.S0 = AM.S0;
718  }
719  else {
720 /*
721  For the moment we don't have special settings.
722  They may become costly in virtual memory.
723 */
724  AT.S0 = AllocSort(AM.S0->LargeSize*sizeof(WORD)/numberofworkers
725  ,AM.S0->SmallSize*sizeof(WORD)/numberofworkers
726  ,AM.S0->SmallEsize*sizeof(WORD)/numberofworkers
727  ,AM.S0->TermsInSmall
728  ,AM.S0->MaxPatches
729 /* ,AM.S0->MaxPatches/numberofworkers */
730  ,AM.S0->MaxFpatches/numberofworkers
731  ,AM.S0->file.POsize);
732  }
733  AR.CompressPointer = AR.CompressBuffer;
734 /*
735  Install the store caches (15-aug-2006 JV)
736 */
737  AT.StoreCache = AT.StoreCacheAlloc = 0;
738  if ( AM.NumStoreCaches > 0 ) {
739  STORECACHE sa, sb;
740  LONG size;
741  size = sizeof(struct StOrEcAcHe)+AM.SizeStoreCache;
742  size = ((size-1)/sizeof(size_t)+1)*sizeof(size_t);
743  AT.StoreCacheAlloc = (STORECACHE)Malloc1(size*AM.NumStoreCaches,"StoreCaches");
744  sa = AT.StoreCache = AT.StoreCacheAlloc;
745  for ( i = 0; i < AM.NumStoreCaches; i++ ) {
746  sb = (STORECACHE)(VOID *)((UBYTE *)sa+size);
747  if ( i == AM.NumStoreCaches-1 ) {
748  sa->next = 0;
749  }
750  else {
751  sa->next = sb;
752  }
753  SETBASEPOSITION(sa->position,-1);
754  SETBASEPOSITION(sa->toppos,-1);
755  sa = sb;
756  }
757  }
758 
759  ReserveTempFiles(2);
760  return(B);
761 OnError:;
762  MLOCK(ErrorMessageLock);
763  MesPrint("Error initializing thread %d",identity);
764  MUNLOCK(ErrorMessageLock);
765  Terminate(-1);
766  return(B);
767 }
768 
769 /*
770  #] InitializeOneThread :
771  #[ FinalizeOneThread :
772 */
783 void FinalizeOneThread(int identity)
784 {
785  timerinfo[identity] = TimeCPU(1);
786 }
787 
788 /*
789  #] FinalizeOneThread :
790  #[ ClearAllThreads :
791 */
798 VOID ClearAllThreads()
799 {
800  int i;
801  MasterWaitAll();
802  for ( i = 1; i <= numberofworkers; i++ ) {
803  WakeupThread(i,CLEARCLOCK);
804  }
805 #ifdef WITHSORTBOTS
806  for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
807  WakeupThread(i,CLEARCLOCK);
808  }
809 #endif
810 }
811 
812 /*
813  #] ClearAllThreads :
814  #[ TerminateAllThreads :
815 */
822 VOID TerminateAllThreads()
823 {
824  int i;
825  for ( i = 1; i <= numberofworkers; i++ ) {
826  GetThread(i);
827  WakeupThread(i,TERMINATETHREAD);
828  }
829 #ifdef WITHSORTBOTS
830  for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
831  WakeupThread(i,TERMINATETHREAD);
832  }
833 #endif
834  for ( i = 1; i <= numberofworkers; i++ ) {
835  pthread_join(threadpointers[i],NULL);
836  }
837 #ifdef WITHSORTBOTS
838  for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
839  pthread_join(threadpointers[i],NULL);
840  }
841 #endif
842 }
843 
844 /*
845  #] TerminateAllThreads :
846  #[ MakeThreadBuckets :
847 */
873 int MakeThreadBuckets(int number, int par)
874 {
875  int i;
876  LONG sizethreadbuckets;
877  THREADBUCKET *thr;
878 /*
879  First we need a decent estimate. Not all terms should be maximal.
880  Note that AM.MaxTer is in bytes!!!
881  Maybe we should try to limit the size here a bit more effectively.
882  This is a great consumer of memory.
883 */
884  sizethreadbuckets = ( AC.ThreadBucketSize + 1 ) * AM.MaxTer + 2*sizeof(WORD);
885  if ( AC.ThreadBucketSize >= 250 ) sizethreadbuckets /= 4;
886  else if ( AC.ThreadBucketSize >= 90 ) sizethreadbuckets /= 3;
887  else if ( AC.ThreadBucketSize >= 40 ) sizethreadbuckets /= 2;
888  sizethreadbuckets /= sizeof(WORD);
889 
890  if ( par == 0 ) {
891  numthreadbuckets = 2*(number-1);
892  threadbuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
893  freebuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
894  }
895  if ( par > 0 ) {
896  if ( sizethreadbuckets <= threadbuckets[0]->threadbuffersize ) return(0);
897  for ( i = 0; i < numthreadbuckets; i++ ) {
898  thr = threadbuckets[i];
899  M_free(thr->deferbuffer,"deferbuffer");
900  }
901  }
902  else {
903  for ( i = 0; i < numthreadbuckets; i++ ) {
904  threadbuckets[i] = (THREADBUCKET *)Malloc1(sizeof(THREADBUCKET),"threadbuckets");
905  threadbuckets[i]->lock = dummylock;
906  }
907  }
908  for ( i = 0; i < numthreadbuckets; i++ ) {
909  thr = threadbuckets[i];
910  thr->threadbuffersize = sizethreadbuckets;
911  thr->free = BUCKETFREE;
912  thr->deferbuffer = (POSITION *)Malloc1(2*sizethreadbuckets*sizeof(WORD)
913  +(AC.ThreadBucketSize+1)*sizeof(POSITION),"deferbuffer");
914  thr->threadbuffer = (WORD *)(thr->deferbuffer+AC.ThreadBucketSize+1);
915  thr->compressbuffer = (WORD *)(thr->threadbuffer+sizethreadbuckets);
916  thr->busy = BUCKETPREPARINGTERM;
917  thr->usenum = thr->totnum = 0;
918  thr->type = BUCKETDOINGTERMS;
919  }
920  return(0);
921 }
922 
923 /*
924  #] MakeThreadBuckets :
925  #[ GetTimerInfo :
926 */
927 
933 int GetTimerInfo(LONG** ti,LONG** sti)
934 {
935  *ti = timerinfo;
936  *sti = sumtimerinfo;
937 #ifdef WITHSORTBOTS
938  return AM.totalnumberofthreads*2;
939 #else
940  return AM.totalnumberofthreads;
941 #endif
942 }
943 
944 /*
945  #] GetTimerInfo :
946  #[ WriteTimerInfo :
947 */
948 
953 void WriteTimerInfo(LONG* ti,LONG* sti)
954 {
955  int i;
956 #ifdef WITHSORTBOTS
957  int max = AM.totalnumberofthreads*2;
958 #else
959  int max = AM.totalnumberofthreads;
960 #endif
961  for ( i=0; i<max; ++i ) {
962  timerinfo[i] = ti[i];
963  sumtimerinfo[i] = sti[i];
964  }
965 }
966 
967 /*
968  #] WriteTimerInfo :
969  #[ GetWorkerTimes :
970 */
976 LONG GetWorkerTimes()
977 {
978  LONG retval = 0;
979  int i;
980  for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
981 #ifdef WITHSORTBOTS
982  for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ )
983  retval += timerinfo[i] + sumtimerinfo[i];
984 #endif
985  return(retval);
986 }
987 
988 /*
989  #] GetWorkerTimes :
990  #[ UpdateOneThread :
991 */
998 int UpdateOneThread(int identity)
999 {
1000  ALLPRIVATES *B = AB[identity], *B0 = AB[0];
1001  AR.GetFile = AR0.GetFile;
1002  AR.KeptInHold = AR0.KeptInHold;
1003  AR.CurExpr = AR0.CurExpr;
1004  AR.SortType = AC.SortType;
1005  if ( AT.WildcardBufferSize < AC.WildcardBufferSize ) {
1006  M_free(AT.WildArgTaken,"argument list names");
1007  AT.WildcardBufferSize = AC.WildcardBufferSize;
1008  AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
1009  ,"argument list names");
1010  if ( AT.WildArgTaken == 0 ) return(-1);
1011  }
1012  return(0);
1013 }
1014 
1015 /*
1016  #] UpdateOneThread :
1017  #[ LoadOneThread :
1018 */
1032 int LoadOneThread(int from, int identity, THREADBUCKET *thr, int par)
1033 {
1034  WORD *t1, *t2;
1035  ALLPRIVATES *B = AB[identity], *B0 = AB[from];
1036 
1037  AR.DefPosition = AR0.DefPosition;
1038  AR.NoCompress = AR0.NoCompress;
1039  AR.gzipCompress = AR0.gzipCompress;
1040  AR.BracketOn = AR0.BracketOn;
1041  AR.CurDum = AR0.CurDum;
1042  AR.DeferFlag = AR0.DeferFlag;
1043  AR.TePos = 0;
1044  AR.sLevel = AR0.sLevel;
1045  AR.Stage4Name = AR0.Stage4Name;
1046  AR.GetOneFile = AR0.GetOneFile;
1047  AR.PolyFun = AR0.PolyFun;
1048  AR.PolyFunInv = AR0.PolyFunInv;
1049  AR.PolyFunType = AR0.PolyFunType;
1050  AR.PolyFunExp = AR0.PolyFunExp;
1051  AR.PolyFunVar = AR0.PolyFunVar;
1052  AR.PolyFunPow = AR0.PolyFunPow;
1053  AR.Eside = AR0.Eside;
1054  AR.Cnumlhs = AR0.Cnumlhs;
1055 /*
1056  AR.MaxBracket = AR0.MaxBracket;
1057 
1058  The compressbuffer contents are mainly relevant for keep brackets
1059  We should do this only if there is a keep brackets statement
1060  We may however still need the compressbuffer for expressions in the rhs.
1061 */
1062  if ( par >= 1 ) {
1063 /*
1064  We may not need this %%%%% 7-apr-2006
1065 */
1066  t1 = AR.CompressBuffer; t2 = AR0.CompressBuffer;
1067  while ( t2 < AR0.CompressPointer ) *t1++ = *t2++;
1068  AR.CompressPointer = t1;
1069 
1070  }
1071  else {
1072  AR.CompressPointer = AR.CompressBuffer;
1073  }
1074  if ( AR.DeferFlag ) {
1075  if ( AR.infile->handle < 0 ) {
1076  AR.infile->POfill = AR0.infile->POfill;
1077  }
1078  else {
1079 /*
1080  We have to set the value of POposition to something that will
1081  force a read in the first try.
1082 */
1083  AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer;
1084  }
1085  }
1086  if ( par == 0 ) {
1087  AN.threadbuck = thr;
1088  AN.ninterms = thr->firstterm;
1089  }
1090  else if ( par == 1 ) {
1091  WORD *tstop;
1092  t1 = thr->threadbuffer; tstop = t1 + *t1;
1093  t2 = AT.WorkPointer;
1094  while ( t1 < tstop ) *t2++ = *t1++;
1095  AN.ninterms = thr->firstterm;
1096  }
1097  AN.TeInFun = 0;
1098  AN.ncmod = AC.ncmod;
1099  AT.BrackBuf = AT0.BrackBuf;
1100  AT.bracketindexflag = AT0.bracketindexflag;
1101  AN.PolyFunTodo = 0;
1102 /*
1103  The relevant variables and the term are in their place.
1104  There is nothing more to do.
1105 */
1106  return(0);
1107 }
1108 
1109 /*
1110  #] LoadOneThread :
1111  #[ BalanceRunThread :
1112 */
1128 int BalanceRunThread(PHEAD int identity, WORD *term, WORD level)
1129 {
1130  GETBIDENTITY
1131  ALLPRIVATES *BB;
1132  WORD *t, *tt;
1133  int i, *ti, *tti;
1134 
1135  LoadOneThread(AT.identity,identity,0,2);
1136 /*
1137  Extra loading if needed. Quantities changed in Generator.
1138  Like the level that has to be passed.
1139 */
1140  BB = AB[identity];
1141  BB->R.level = level;
1142  BB->T.TMbuff = AT.TMbuff;
1143  ti = AT.RepCount; tti = BB->T.RepCount;
1144  i = AN.RepPoint - AT.RepCount;
1145  BB->N.RepPoint = BB->T.RepCount + i;
1146  for ( ; i >= 0; i-- ) tti[i] = ti[i];
1147 
1148  t = term; i = *term;
1149  tt = BB->T.WorkSpace;
1150  NCOPY(tt,t,i);
1151  BB->T.WorkPointer = tt;
1152 
1153  WakeupThread(identity,HIGHERLEVELGENERATION);
1154 
1155  return(0);
1156 }
1157 
1158 /*
1159  #] BalanceRunThread :
1160  #[ SetWorkerFiles :
1161 */
1166 void SetWorkerFiles()
1167 {
1168  int id;
1169  ALLPRIVATES *B, *B0 = AB[0];
1170  for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
1171  B = AB[id];
1172  AR.infile = &(AR.Fscr[0]);
1173  AR.outfile = &(AR.Fscr[1]);
1174  AR.hidefile = &(AR.Fscr[2]);
1175  AR.infile->handle = AR0.infile->handle;
1176  AR.hidefile->handle = AR0.hidefile->handle;
1177  if ( AR.infile->handle < 0 ) {
1178  AR.infile->PObuffer = AR0.infile->PObuffer;
1179  AR.infile->POstop = AR0.infile->POstop;
1180  AR.infile->POfill = AR0.infile->POfill;
1181  AR.infile->POfull = AR0.infile->POfull;
1182  AR.infile->POsize = AR0.infile->POsize;
1183  AR.InInBuf = AR0.InInBuf;
1184  AR.infile->POposition = AR0.infile->POposition;
1185  AR.infile->filesize = AR0.infile->filesize;
1186  }
1187  else {
1188  AR.infile->PObuffer = AR.infile->wPObuffer;
1189  AR.infile->POstop = AR.infile->wPOstop;
1190  AR.infile->POfill = AR.infile->wPOfill;
1191  AR.infile->POfull = AR.infile->wPOfull;
1192  AR.infile->POsize = AR.infile->wPOsize;
1193  AR.InInBuf = 0;
1194  PUTZERO(AR.infile->POposition);
1195  }
1196 /*
1197  If there is some writing, it betters happens to ones own outfile.
1198  Currently this is to be done only for InParallel.
1199  Merging of the outputs is then done by the CopyExpression routine.
1200 */
1201  {
1202  AR.outfile->PObuffer = AR.outfile->wPObuffer;
1203  AR.outfile->POstop = AR.outfile->wPOstop;
1204  AR.outfile->POfill = AR.outfile->wPOfill;
1205  AR.outfile->POfull = AR.outfile->wPOfull;
1206  AR.outfile->POsize = AR.outfile->wPOsize;
1207  PUTZERO(AR.outfile->POposition);
1208  }
1209  if ( AR.hidefile->handle < 0 ) {
1210  AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
1211  AR.hidefile->POstop = AR0.hidefile->POstop;
1212  AR.hidefile->POfill = AR0.hidefile->POfill;
1213  AR.hidefile->POfull = AR0.hidefile->POfull;
1214  AR.hidefile->POsize = AR0.hidefile->POsize;
1215  AR.InHiBuf = AR0.InHiBuf;
1216  AR.hidefile->POposition = AR0.hidefile->POposition;
1217  AR.hidefile->filesize = AR0.hidefile->filesize;
1218  }
1219  else {
1220  AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
1221  AR.hidefile->POstop = AR.hidefile->wPOstop;
1222  AR.hidefile->POfill = AR.hidefile->wPOfill;
1223  AR.hidefile->POfull = AR.hidefile->wPOfull;
1224  AR.hidefile->POsize = AR.hidefile->wPOsize;
1225  AR.InHiBuf = 0;
1226  PUTZERO(AR.hidefile->POposition);
1227  }
1228  }
1229  if ( AR0.StoreData.dirtyflag ) {
1230  for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
1231  B = AB[id];
1232  AR.StoreData = AR0.StoreData;
1233  }
1234  }
1235 }
1236 
1237 /*
1238  #] SetWorkerFiles :
1239  #[ RunThread :
1240 */
1248 void *RunThread(void *dummy)
1249 {
1250  WORD *term, *ttin, *tt, *ttco, *oldwork;
1251  int identity, wakeupsignal, identityretv, i, tobereleased, errorcode;
1252  ALLPRIVATES *B;
1253  THREADBUCKET *thr;
1254  POSITION *ppdef;
1255  EXPRESSIONS e;
1256  DUMMYUSE(dummy);
1257  identity = SetIdentity(&identityretv);
1258  threadpointers[identity] = pthread_self();
1259  B = InitializeOneThread(identity);
1260  while ( ( wakeupsignal = ThreadWait(identity) ) > 0 ) {
1261  switch ( wakeupsignal ) {
1262 /*
1263  #[ STARTNEWEXPRESSION :
1264 */
1265  case STARTNEWEXPRESSION:
1266 /*
1267  Set up the sort routines etc.
1268  Start with getting some buffers synchronized with the compiler
1269 */
1270  if ( UpdateOneThread(identity) ) {
1271  MLOCK(ErrorMessageLock);
1272  MesPrint("Update error in starting expression in thread %d in module %d",identity,AC.CModule);
1273  MUNLOCK(ErrorMessageLock);
1274  Terminate(-1);
1275  }
1276  AR.DeferFlag = AC.ComDefer;
1277  AR.sLevel = AS.sLevel;
1278  AR.MaxDum = AM.IndDum;
1279  AR.expchanged = AB[0]->R.expchanged;
1280  AR.expflags = AB[0]->R.expflags;
1281  AR.PolyFun = AB[0]->R.PolyFun;
1282  AR.PolyFunInv = AB[0]->R.PolyFunInv;
1283  AR.PolyFunType = AB[0]->R.PolyFunType;
1284  AR.PolyFunExp = AB[0]->R.PolyFunExp;
1285  AR.PolyFunVar = AB[0]->R.PolyFunVar;
1286  AR.PolyFunPow = AB[0]->R.PolyFunPow;
1287 /*
1288  Now fire up the sort buffer.
1289 */
1290  NewSort(BHEAD0);
1291  break;
1292 /*
1293  #] STARTNEWEXPRESSION :
1294  #[ LOWESTLEVELGENERATION :
1295 */
1296  case LOWESTLEVELGENERATION:
1297 #ifdef INNERTEST
1298  if ( AC.InnerTest ) {
1299  if ( StrCmp(AC.TestValue,(UBYTE *)INNERTEST) == 0 ) {
1300  MesPrint("Testing(Worker%d): value = %s",AT.identity,AC.TestValue);
1301  }
1302  }
1303 #endif
1304  e = Expressions + AR.CurExpr;
1305  thr = AN.threadbuck;
1306  ppdef = thr->deferbuffer;
1307  ttin = thr->threadbuffer;
1308  ttco = thr->compressbuffer;
1309  term = AT.WorkPointer;
1310  thr->usenum = 0;
1311  tobereleased = 0;
1312  AN.inputnumber = thr->firstterm;
1313  AN.ninterms = thr->firstterm;
1314  do {
1315  thr->usenum++; /* For if the master wants to steal the bucket */
1316  tt = term; i = *ttin;
1317  NCOPY(tt,ttin,i);
1318  AT.WorkPointer = tt;
1319  if ( AR.DeferFlag ) {
1320  tt = AR.CompressBuffer; i = *ttco;
1321  NCOPY(tt,ttco,i);
1322  AR.CompressPointer = tt;
1323  AR.DefPosition = ppdef[0]; ppdef++;
1324  }
1325  if ( thr->free == BUCKETTERMINATED ) {
1326 /*
1327  The next statement allows the master to steal the bucket
1328  for load balancing purposes. We do still execute the current
1329  term, but afterwards we drop out.
1330  Once we have written the release code, we cannot use this
1331  bucket anymore. Hence the exit to the label bucketstolen.
1332 */
1333  if ( thr->usenum == thr->totnum ) {
1334  thr->free = BUCKETCOMINGFREE;
1335  }
1336  else {
1337  thr->free = BUCKETRELEASED;
1338  tobereleased = 1;
1339  }
1340  }
1341 /*
1342  What if we want to steal and we set thr->free while
1343  the thread is inside the next code for a long time?
1344  if ( AT.LoadBalancing ) {
1345 */
1346  LOCK(thr->lock);
1347  thr->busy = BUCKETDOINGTERM;
1348  UNLOCK(thr->lock);
1349 /*
1350  }
1351  else {
1352  thr->busy = BUCKETDOINGTERM;
1353  }
1354 */
1355  AN.RepPoint = AT.RepCount + 1;
1356 
1357  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1358  StoreTerm(BHEAD term);
1359  }
1360  else {
1361  if ( AR.DeferFlag ) {
1362  AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
1363  }
1364  else {
1365  AN.IndDum = AM.IndDum;
1366  AR.CurDum = ReNumber(BHEAD term);
1367  }
1368  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1369  if ( AN.ncmod ) {
1370  if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1371  else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1372  }
1373  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1374  if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
1375  MLOCK(ErrorMessageLock);
1376  MesPrint("Thread %w executing term:");
1377  PrintTerm(term,"LLG");
1378  MUNLOCK(ErrorMessageLock);
1379  }
1380  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1381  && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1382  PolyFunClean(BHEAD term);
1383  }
1384  if ( Generator(BHEAD term,0) ) {
1385  LowerSortLevel();
1386  MLOCK(ErrorMessageLock);
1387  MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
1388  MUNLOCK(ErrorMessageLock);
1389  Terminate(-1);
1390  }
1391  AN.ninterms++;
1392  }
1393 /* if ( AT.LoadBalancing ) { */
1394  LOCK(thr->lock);
1395  thr->busy = BUCKETPREPARINGTERM;
1396  UNLOCK(thr->lock);
1397 /*
1398  }
1399  else {
1400  thr->busy = BUCKETPREPARINGTERM;
1401  }
1402 */
1403  if ( thr->free == BUCKETTERMINATED ) {
1404  if ( thr->usenum == thr->totnum ) {
1405  thr->free = BUCKETCOMINGFREE;
1406  }
1407  else {
1408  thr->free = BUCKETRELEASED;
1409  tobereleased = 1;
1410  }
1411  }
1412  if ( tobereleased ) goto bucketstolen;
1413  } while ( *ttin );
1414  thr->free = BUCKETCOMINGFREE;
1415 bucketstolen:;
1416 /* if ( AT.LoadBalancing ) { */
1417  LOCK(thr->lock);
1418  thr->busy = BUCKETTOBERELEASED;
1419  UNLOCK(thr->lock);
1420 /* }
1421  else {
1422  thr->busy = BUCKETTOBERELEASED;
1423  }
1424 */
1425  AT.WorkPointer = term;
1426  break;
1427 /*
1428  #] LOWESTLEVELGENERATION :
1429  #[ FINISHEXPRESSION :
1430 */
1431 #ifdef WITHSORTBOTS
1432  case CLAIMOUTPUT:
1433  LOCK(AT.SB.MasterBlockLock[1]);
1434  break;
1435 #endif
1436  case FINISHEXPRESSION:
1437 /*
1438  Finish the sort
1439 
1440  Start with claiming the first block
1441  Once we have claimed it we can let the master know that
1442  everything is all right.
1443 */
1444  LOCK(AT.SB.MasterBlockLock[1]);
1445  ThreadClaimedBlock(identity);
1446 /*
1447  Entry for when we work with sortbots
1448 */
1449 #ifdef WITHSORTBOTS
1450  case FINISHEXPRESSION2:
1451 #endif
1452 /*
1453  Now we may need here an fsync on the sort file
1454 */
1455  if ( AC.ThreadSortFileSynch ) {
1456  if ( AT.S0->file.handle >= 0 ) {
1457  SynchFile(AT.S0->file.handle);
1458  }
1459  }
1460  AT.SB.FillBlock = 1;
1461  AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
1462  errorcode = EndSort(BHEAD AT.S0->sBuffer,0);
1463  UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
1464  UpdateMaxSize();
1465  if ( errorcode ) {
1466  MLOCK(ErrorMessageLock);
1467  MesPrint("Error terminating sort in thread %d in module %d",identity,AC.CModule);
1468  MUNLOCK(ErrorMessageLock);
1469  Terminate(-1);
1470  }
1471  break;
1472 /*
1473  #] FINISHEXPRESSION :
1474  #[ CLEANUPEXPRESSION :
1475 */
1476  case CLEANUPEXPRESSION:
1477 /*
1478  Cleanup everything and wait for the next expression
1479 */
1480  if ( AR.outfile->handle >= 0 ) {
1481  CloseFile(AR.outfile->handle);
1482  AR.outfile->handle = -1;
1483  remove(AR.outfile->name);
1484  AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
1485  PUTZERO(AR.outfile->POposition);
1486  PUTZERO(AR.outfile->filesize);
1487  }
1488  else {
1489  AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
1490  PUTZERO(AR.outfile->POposition);
1491  PUTZERO(AR.outfile->filesize);
1492  }
1493  {
1494  CBUF *C = cbuf+AT.ebufnum;
1495  WORD **w, ii;
1496  if ( C->numrhs > 0 || C->numlhs > 0 ) {
1497  if ( C->rhs ) {
1498  w = C->rhs; ii = C->numrhs;
1499  do { *w++ = 0; } while ( --ii > 0 );
1500  }
1501  if ( C->lhs ) {
1502  w = C->lhs; ii = C->numlhs;
1503  do { *w++ = 0; } while ( --ii > 0 );
1504  }
1505  C->numlhs = C->numrhs = 0;
1506  ClearTree(AT.ebufnum);
1507  C->Pointer = C->Buffer;
1508  }
1509  }
1510  break;
1511 /*
1512  #] CLEANUPEXPRESSION :
1513  #[ HIGHERLEVELGENERATION :
1514 */
1515  case HIGHERLEVELGENERATION:
1516 /*
1517  When foliating halfway the tree.
1518  This should only be needed in a second level load balancing
1519 */
1520  term = AT.WorkSpace; AT.WorkPointer = term + *term;
1521  if ( Generator(BHEAD term,AR.level) ) {
1522  LowerSortLevel();
1523  MLOCK(ErrorMessageLock);
1524  MesPrint("Error in load balancing one term at level %d in thread %d in module %d",AR.level,AT.identity,AC.CModule);
1525  MUNLOCK(ErrorMessageLock);
1526  Terminate(-1);
1527  }
1528  AT.WorkPointer = term;
1529  break;
1530 /*
1531  #] HIGHERLEVELGENERATION :
1532  #[ STARTNEWMODULE :
1533 */
1534  case STARTNEWMODULE:
1535 /*
1536  For resetting variables.
1537 */
1538  SpecialCleanup(B);
1539  break;
1540 /*
1541  #] STARTNEWMODULE :
1542  #[ TERMINATETHREAD :
1543 */
1544  case TERMINATETHREAD:
1545  goto EndOfThread;
1546 /*
1547  #] TERMINATETHREAD :
1548  #[ DOONEEXPRESSION :
1549 
1550  When a thread has to do a complete (not too big) expression.
1551  The number of the expression to be done is in AR.exprtodo.
1552  The code is mostly taken from Processor. The only difference
1553  is with what to do with the output.
1554  The output should go to the scratch buffer of the worker
1555  (which is free at the right moment). If this buffer is too
1556  small we have a problem. We could write to file or give the
1557  master what we have and from now on the master has to collect
1558  pieces until things are complete.
1559  Note: this assumes that the expressions don't keep their order.
1560  If they have to keep their order, don't use this feature.
1561 */
1562  case DOONEEXPRESSION: {
1563 
1564  POSITION position, outposition;
1565  FILEHANDLE *fi, *fout, *oldoutfile;
1566  LONG dd = 0;
1567  WORD oldBracketOn = AR.BracketOn;
1568  WORD *oldBrackBuf = AT.BrackBuf;
1569  WORD oldbracketindexflag = AT.bracketindexflag;
1570  WORD fromspectator = 0;
1571  e = Expressions + AR.exprtodo;
1572  i = AR.exprtodo;
1573  AR.CurExpr = i;
1574  AR.SortType = AC.SortType;
1575  AR.expchanged = 0;
1576  if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
1577  AR.BracketOn = 1;
1578  AT.BrackBuf = AM.BracketFactors;
1579  AT.bracketindexflag = 1;
1580  }
1581 
1582  position = AS.OldOnFile[i];
1583  if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION ) {
1584  AR.GetFile = 2; fi = AR.hidefile;
1585  }
1586  else {
1587  AR.GetFile = 0; fi = AR.infile;
1588  }
1589 /*
1590  PUTZERO(fi->POposition);
1591  if ( fi->handle >= 0 ) {
1592  fi->POfill = fi->POfull = fi->PObuffer;
1593  }
1594 */
1595  SetScratch(fi,&position);
1596  term = oldwork = AT.WorkPointer;
1597  AR.CompressPointer = AR.CompressBuffer;
1598  AR.CompressPointer[0] = 0;
1599  AR.KeptInHold = 0;
1600  if ( GetTerm(BHEAD term) <= 0 ) {
1601  MLOCK(ErrorMessageLock);
1602  MesPrint("Expression %d has problems in scratchfile (t)",i);
1603  MUNLOCK(ErrorMessageLock);
1604  Terminate(-1);
1605  }
1606  if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
1607  term[3] = i;
1608  if ( term[5] < 0 ) {
1609  fromspectator = -term[5];
1610  PUTZERO(AM.SpectatorFiles[fromspectator-1].readpos);
1611  term[5] = AC.cbufnum;
1612  }
1613  PUTZERO(outposition);
1614  fout = AR.outfile;
1615  fout->POfill = fout->POfull = fout->PObuffer;
1616  fout->POposition = outposition;
1617  if ( fout->handle >= 0 ) {
1618  fout->POposition = outposition;
1619  }
1620 /*
1621  The next statement is needed because we need the system
1622  to believe that the expression is at position zero for
1623  the moment. In this worker, with no memory of other expressions,
1624  it is. This is needed for when a bracket index is made
1625  because there e->onfile is an offset. Afterwards, when the
1626  expression is written to its final location in the masters
1627  output e->onfile will get its real value.
1628 */
1629  PUTZERO(e->onfile);
1630  if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) goto ProcErr;
1631 
1632  AR.DeferFlag = AC.ComDefer;
1633 
1634  AR.sLevel = AB[0]->R.sLevel;
1635  term = AT.WorkPointer;
1636  NewSort(BHEAD0);
1637  AR.MaxDum = AM.IndDum;
1638  AN.ninterms = 0;
1639  if ( fromspectator ) {
1640  while ( GetFromSpectator(term,fromspectator-1) ) {
1641  AT.WorkPointer = term + *term;
1642  AN.RepPoint = AT.RepCount + 1;
1643  AN.IndDum = AM.IndDum;
1644  AR.CurDum = ReNumber(BHEAD term);
1645  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1646  if ( AN.ncmod ) {
1647  if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1648  else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1649  }
1650  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1651  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1652  && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1653  PolyFunClean(BHEAD term);
1654  }
1655  if ( Generator(BHEAD term,0) ) {
1656  LowerSortLevel(); goto ProcErr;
1657  }
1658  }
1659  }
1660  else {
1661  while ( GetTerm(BHEAD term) ) {
1662  SeekScratch(fi,&position);
1663  AN.ninterms++; dd = AN.deferskipped;
1664  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1665  StoreTerm(BHEAD term);
1666  }
1667  else {
1668  if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
1669  if ( GetMoreTerms(term) < 0 ) {
1670  LowerSortLevel(); goto ProcErr;
1671  }
1672  SeekScratch(fi,&position);
1673  }
1674  AT.WorkPointer = term + *term;
1675  AN.RepPoint = AT.RepCount + 1;
1676  if ( AR.DeferFlag ) {
1677  AR.CurDum = AN.IndDum = Expressions[AR.exprtodo].numdummies;
1678  }
1679  else {
1680  AN.IndDum = AM.IndDum;
1681  AR.CurDum = ReNumber(BHEAD term);
1682  }
1683  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1684  if ( AN.ncmod ) {
1685  if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1686  else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1687  }
1688  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1689  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1690  && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1691  PolyFunClean(BHEAD term);
1692  }
1693  if ( Generator(BHEAD term,0) ) {
1694  LowerSortLevel(); goto ProcErr;
1695  }
1696  AN.ninterms += dd;
1697  }
1698  SetScratch(fi,&position);
1699  if ( fi == AR.hidefile ) {
1700  AR.InHiBuf = (fi->POfull-fi->PObuffer)
1701  -DIFBASE(position,fi->POposition)/sizeof(WORD);
1702  }
1703  else {
1704  AR.InInBuf = (fi->POfull-fi->PObuffer)
1705  -DIFBASE(position,fi->POposition)/sizeof(WORD);
1706  }
1707  }
1708  }
1709  AN.ninterms += dd;
1710  if ( EndSort(BHEAD AT.S0->sBuffer,0) < 0 ) goto ProcErr;
1711  e->numdummies = AR.MaxDum - AM.IndDum;
1712  AR.BracketOn = oldBracketOn;
1713  AT.BrackBuf = oldBrackBuf;
1714  if ( ( e->vflags & TOBEFACTORED ) != 0 )
1715  poly_factorize_expression(e);
1716  else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
1717  && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
1718  poly_unfactorize_expression(e);
1719  if ( AT.S0->TermsLeft ) e->vflags &= ~ISZERO;
1720  else e->vflags |= ISZERO;
1721  if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
1722  if ( AT.S0->TermsLeft ) AR.expflags |= ISZERO;
1723  if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;
1724  AR.GetFile = 0;
1725  AT.bracketindexflag = oldbracketindexflag;
1726 /*
1727  Now copy the whole thing from fout to AR0.outfile
1728  Do this in one go to keep the lock occupied as short as possible
1729 */
1730  SeekScratch(fout,&outposition);
1731  LOCK(AS.outputslock);
1732  oldoutfile = AB[0]->R.outfile;
1733  if ( e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
1734  AB[0]->R.outfile = AB[0]->R.hidefile;
1735  }
1736  SeekScratch(AB[0]->R.outfile,&position);
1737  e->onfile = position;
1738  if ( CopyExpression(fout,AB[0]->R.outfile) < 0 ) {
1739  AB[0]->R.outfile = oldoutfile;
1740  UNLOCK(AS.outputslock);
1741  MLOCK(ErrorMessageLock);
1742  MesPrint("Error copying output of 'InParallel' expression to master. Thread: %d",identity);
1743  MUNLOCK(ErrorMessageLock);
1744  goto ProcErr;
1745  }
1746  AB[0]->R.outfile = oldoutfile;
1747  AB[0]->R.hidefile->POfull = AB[0]->R.hidefile->POfill;
1748  AB[0]->R.expflags = AR.expflags;
1749  UNLOCK(AS.outputslock);
1750 
1751  if ( fout->handle >= 0 ) { /* Now get rid of the file */
1752  CloseFile(fout->handle);
1753  fout->handle = -1;
1754  remove(fout->name);
1755  PUTZERO(fout->POposition);
1756  PUTZERO(fout->filesize);
1757  fout->POfill = fout->POfull = fout->PObuffer;
1758  }
1759  UpdateMaxSize();
1760 
1761  AT.WorkPointer = oldwork;
1762 
1763  } break;
1764 /*
1765  #] DOONEEXPRESSION :
1766  #[ DOBRACKETS :
1767 
1768  In case we have a bracket index we can have the worker treat
1769  one or more of the entries in the bracket index.
1770  The advantage is that identical terms will meet each other
1771  sooner in the sorting and hence fewer compares will be needed.
1772  Also this way the master doesn't need to fill the buckets.
1773  The main problem is the load balancing which can become very
1774  bad when there is a long tail without things outside the bracket.
1775 
1776  We get sent:
1777  1: The number of the first bracket to be done
1778  2: The number of the last bracket to be done
1779 */
1780  case DOBRACKETS: {
1781  BRACKETINFO *binfo;
1782  BRACKETINDEX *bi;
1783  FILEHANDLE *fi;
1784  POSITION stoppos,where;
1785  e = Expressions + AR.CurExpr;
1786  binfo = e->bracketinfo;
1787  thr = AN.threadbuck;
1788  bi = &(binfo->indexbuffer[thr->firstbracket]);
1789  if ( AR.GetFile == 2 ) fi = AR.hidefile;
1790  else fi = AR.infile;
1791  where = bi->start;
1792  ADD2POS(where,AS.OldOnFile[AR.CurExpr]);
1793  SetScratch(fi,&(where));
1794  stoppos = binfo->indexbuffer[thr->lastbracket].next;
1795  ADD2POS(stoppos,AS.OldOnFile[AR.CurExpr]);
1796  AN.ninterms = thr->firstterm;
1797 /*
1798  Now we have to put the 'value' of the bracket in the
1799  Compress buffer.
1800 */
1801  ttco = AR.CompressBuffer;
1802  tt = binfo->bracketbuffer + bi->bracket;
1803  i = *tt;
1804  NCOPY(ttco,tt,i)
1805  AR.CompressPointer = ttco;
1806  term = AT.WorkPointer;
1807  while ( GetTerm(BHEAD term) ) {
1808  SeekScratch(fi,&where);
1809  AT.WorkPointer = term + *term;
1810  AN.IndDum = AM.IndDum;
1811  AR.CurDum = ReNumber(BHEAD term);
1812  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1813  if ( AN.ncmod ) {
1814  if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1815  else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1816  }
1817  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1818  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1819  && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1820  PolyFunClean(BHEAD term);
1821  }
1822  if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
1823  MLOCK(ErrorMessageLock);
1824  MesPrint("Thread %w executing term:");
1825  PrintTerm(term,"DoBrackets");
1826  MUNLOCK(ErrorMessageLock);
1827  }
1828  AT.WorkPointer = term + *term;
1829  if ( Generator(BHEAD term,0) ) {
1830  LowerSortLevel();
1831  MLOCK(ErrorMessageLock);
1832  MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
1833  MUNLOCK(ErrorMessageLock);
1834  Terminate(-1);
1835  }
1836  AN.ninterms++;
1837  SetScratch(fi,&(where));
1838  if ( ISGEPOS(where,stoppos) ) break;
1839  }
1840  AT.WorkPointer = term;
1841  thr->free = BUCKETCOMINGFREE;
1842  break;
1843  }
1844 /*
1845  #] DOBRACKETS :
1846  #[ CLEARCLOCK :
1847 
1848  The program only comes here after a .clear
1849 */
1850  case CLEARCLOCK:
1851 /* LOCK(clearclocklock); */
1852  sumtimerinfo[identity] += TimeCPU(1);
1853  timerinfo[identity] = TimeCPU(0);
1854 /* UNLOCK(clearclocklock); */
1855  break;
1856 /*
1857  #] CLEARCLOCK :
1858  #[ MCTSEXPANDTREE :
1859 */
1860  case MCTSEXPANDTREE:
1861  AT.optimtimes = AB[0]->T.optimtimes;
1862  find_Horner_MCTS_expand_tree();
1863  break;
1864 /*
1865  #] MCTSEXPANDTREE :
1866  #[ OPTIMIZEEXPRESSION :
1867 */
1868  case OPTIMIZEEXPRESSION:
1869  optimize_expression_given_Horner();
1870  break;
1871 /*
1872  #] OPTIMIZEEXPRESSION :
1873 */
1874  default:
1875  MLOCK(ErrorMessageLock);
1876  MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
1877  MUNLOCK(ErrorMessageLock);
1878  Terminate(-1);
1879  break;
1880  }
1881  /* we need the following update in case we are using checkpoints. then we
1882  need to readjust the clocks when recovering using this information */
1883  timerinfo[identity] = TimeCPU(1);
1884  }
1885 EndOfThread:;
1886 /*
1887  This is the end of the thread. We cleanup and exit.
1888 */
1889  FinalizeOneThread(identity);
1890  return(0);
1891 ProcErr:
1892  Terminate(-1);
1893  return(0);
1894 }
1895 
1896 /*
1897  #] RunThread :
1898  #[ RunSortBot :
1899 */
1907 #ifdef WITHSORTBOTS
1908 
1909 void *RunSortBot(void *dummy)
1910 {
1911  int identity, wakeupsignal, identityretv;
1912  ALLPRIVATES *B, *BB;
1913  DUMMYUSE(dummy);
1914  identity = SetIdentity(&identityretv);
1915  threadpointers[identity] = pthread_self();
1916  B = InitializeOneThread(identity);
1917  while ( ( wakeupsignal = SortBotWait(identity) ) > 0 ) {
1918  switch ( wakeupsignal ) {
1919 /*
1920  #[ INISORTBOT :
1921 */
1922  case INISORTBOT:
1923  AR.CurExpr = AB[0]->R.CurExpr;
1924  AR.PolyFun = AB[0]->R.PolyFun;
1925  AR.PolyFunInv = AB[0]->R.PolyFunInv;
1926  AR.PolyFunType = AB[0]->R.PolyFunType;
1927  AR.PolyFunExp = AB[0]->R.PolyFunExp;
1928  AR.PolyFunVar = AB[0]->R.PolyFunVar;
1929  AR.PolyFunPow = AB[0]->R.PolyFunPow;
1930  AR.SortType = AC.SortType;
1931  if ( AR.PolyFun == 0 ) { AT.SS->PolyFlag = 0; }
1932  else if ( AR.PolyFunType == 1 ) { AT.SS->PolyFlag = 1; }
1933  else if ( AR.PolyFunType == 2 ) {
1934  if ( AR.PolyFunExp == 2
1935  || AR.PolyFunExp == 3 ) AT.SS->PolyFlag = 1;
1936  else AT.SS->PolyFlag = 2;
1937  }
1938  AT.SS->PolyWise = 0;
1939  AN.ncmod = AC.ncmod;
1940  LOCK(AT.SB.MasterBlockLock[1]);
1941  BB = AB[AT.SortBotIn1];
1942  LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
1943  BB = AB[AT.SortBotIn2];
1944  LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
1945  AT.SB.FillBlock = 1;
1946  AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
1947  SETBASEPOSITION(AN.theposition,0);
1948  break;
1949 /*
1950  #] INISORTBOT :
1951  #[ RUNSORTBOT :
1952 */
1953  case RUNSORTBOT:
1954  SortBotMerge(B);
1955  break;
1956 /*
1957  #] RUNSORTBOT :
1958  #[ TERMINATETHREAD :
1959 */
1960  case TERMINATETHREAD:
1961  goto EndOfThread;
1962 /*
1963  #] TERMINATETHREAD :
1964  #[ CLEARCLOCK :
1965 
1966  The program only comes here after a .clear
1967 */
1968  case CLEARCLOCK:
1969 /* LOCK(clearclocklock); */
1970  sumtimerinfo[identity] += TimeCPU(1);
1971  timerinfo[identity] = TimeCPU(0);
1972 /* UNLOCK(clearclocklock); */
1973  break;
1974 /*
1975  #] CLEARCLOCK :
1976 */
1977  default:
1978  MLOCK(ErrorMessageLock);
1979  MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
1980  MUNLOCK(ErrorMessageLock);
1981  Terminate(-1);
1982  break;
1983  }
1984  }
1985 EndOfThread:;
1986 /*
1987  This is the end of the thread. We cleanup and exit.
1988 */
1989  FinalizeOneThread(identity);
1990  return(0);
1991 }
1992 
1993 #endif
1994 
1995 /*
1996  #] RunSortBot :
1997  #[ IAmAvailable :
1998 */
2010 void IAmAvailable(int identity)
2011 {
2012  int top;
2013  LOCK(availabilitylock);
2014  top = topofavailables;
2015  listofavailables[topofavailables++] = identity;
2016  if ( top == 0 ) {
2017  UNLOCK(availabilitylock);
2018  LOCK(wakeupmasterlock);
2019  wakeupmaster = identity;
2020  pthread_cond_signal(&wakeupmasterconditions);
2021  UNLOCK(wakeupmasterlock);
2022  }
2023  else {
2024  UNLOCK(availabilitylock);
2025  }
2026 }
2027 
2028 /*
2029  #] IAmAvailable :
2030  #[ GetAvailableThread :
2031 */
2040 int GetAvailableThread()
2041 {
2042  int retval = -1;
2043  LOCK(availabilitylock);
2044  if ( topofavailables > 0 ) retval = listofavailables[--topofavailables];
2045  UNLOCK(availabilitylock);
2046  if ( retval >= 0 ) {
2047 /*
2048  Make sure the thread is indeed waiting and not between
2049  saying that it is available and starting to wait.
2050 */
2051  LOCK(wakeuplocks[retval]);
2052  UNLOCK(wakeuplocks[retval]);
2053  }
2054  return(retval);
2055 }
2056 
2057 /*
2058  #] GetAvailableThread :
2059  #[ ConditionalGetAvailableThread :
2060 */
2068 int ConditionalGetAvailableThread()
2069 {
2070  int retval = -1;
2071  if ( topofavailables > 0 ) {
2072  LOCK(availabilitylock);
2073  if ( topofavailables > 0 ) {
2074  retval = listofavailables[--topofavailables];
2075  }
2076  UNLOCK(availabilitylock);
2077  if ( retval >= 0 ) {
2078 /*
2079  Make sure the thread is indeed waiting and not between
2080  saying that it is available and starting to wait.
2081 */
2082  LOCK(wakeuplocks[retval]);
2083  UNLOCK(wakeuplocks[retval]);
2084  }
2085  }
2086  return(retval);
2087 }
2088 
2089 /*
2090  #] ConditionalGetAvailableThread :
2091  #[ GetThread :
2092 */
2102 int GetThread(int identity)
2103 {
2104  int retval = -1, j;
2105  LOCK(availabilitylock);
2106  for ( j = 0; j < topofavailables; j++ ) {
2107  if ( identity == listofavailables[j] ) break;
2108  }
2109  if ( j < topofavailables ) {
2110  --topofavailables;
2111  for ( ; j < topofavailables; j++ ) {
2112  listofavailables[j] = listofavailables[j+1];
2113  }
2114  retval = identity;
2115  }
2116  UNLOCK(availabilitylock);
2117  return(retval);
2118 }
2119 
2120 /*
2121  #] GetThread :
2122  #[ ThreadWait :
2123 */
2133 int ThreadWait(int identity)
2134 {
2135  int retval, top, j;
2136  LOCK(wakeuplocks[identity]);
2137  LOCK(availabilitylock);
2138  top = topofavailables;
2139  for ( j = topofavailables; j > 0; j-- )
2140  listofavailables[j] = listofavailables[j-1];
2141  listofavailables[0] = identity;
2142  topofavailables++;
2143  if ( top == 0 || topofavailables == numberofworkers ) {
2144  UNLOCK(availabilitylock);
2145  LOCK(wakeupmasterlock);
2146  wakeupmaster = identity;
2147  pthread_cond_signal(&wakeupmasterconditions);
2148  UNLOCK(wakeupmasterlock);
2149  }
2150  else {
2151  UNLOCK(availabilitylock);
2152  }
2153  while ( wakeup[identity] == 0 ) {
2154  pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
2155  }
2156  retval = wakeup[identity];
2157  wakeup[identity] = 0;
2158  UNLOCK(wakeuplocks[identity]);
2159  return(retval);
2160 }
2161 
2162 /*
2163  #] ThreadWait :
2164  #[ SortBotWait :
2165 */
2166 
2167 #ifdef WITHSORTBOTS
2168 
2177 int SortBotWait(int identity)
2178 {
2179  int retval;
2180  LOCK(wakeuplocks[identity]);
2181  LOCK(availabilitylock);
2182  topsortbotavailables++;
2183  if ( topsortbotavailables >= numberofsortbots ) {
2184  UNLOCK(availabilitylock);
2185  LOCK(wakeupsortbotlock);
2186  wakeupmaster = identity;
2187  pthread_cond_signal(&wakeupsortbotconditions);
2188  UNLOCK(wakeupsortbotlock);
2189  }
2190  else {
2191  UNLOCK(availabilitylock);
2192  }
2193  while ( wakeup[identity] == 0 ) {
2194  pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
2195  }
2196  retval = wakeup[identity];
2197  wakeup[identity] = 0;
2198  UNLOCK(wakeuplocks[identity]);
2199  return(retval);
2200 }
2201 
2202 #endif
2203 
2204 /*
2205  #] SortBotWait :
2206  #[ ThreadClaimedBlock :
2207 */
2218 int ThreadClaimedBlock(int identity)
2219 {
2220  LOCK(availabilitylock);
2221  numberclaimed++;
2222  if ( numberclaimed >= numberofworkers ) {
2223  UNLOCK(availabilitylock);
2224  LOCK(wakeupmasterlock);
2225  wakeupmaster = identity;
2226  pthread_cond_signal(&wakeupmasterconditions);
2227  UNLOCK(wakeupmasterlock);
2228  }
2229  else {
2230  UNLOCK(availabilitylock);
2231  }
2232  return(0);
2233 }
2234 
2235 /*
2236  #] ThreadClaimedBlock :
2237  #[ MasterWait :
2238 */
2246 int MasterWait()
2247 {
2248  int retval;
2249  LOCK(wakeupmasterlock);
2250  while ( wakeupmaster == 0 ) {
2251  pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2252  }
2253  retval = wakeupmaster;
2254  wakeupmaster = 0;
2255  UNLOCK(wakeupmasterlock);
2256  return(retval);
2257 }
2258 
2259 /*
2260  #] MasterWait :
2261  #[ MasterWaitThread :
2262 */
2269 int MasterWaitThread(int identity)
2270 {
2271  int retval;
2272  LOCK(wakeupmasterthreadlocks[identity]);
2273  while ( wakeupmasterthread[identity] == 0 ) {
2274  pthread_cond_wait(&(wakeupmasterthreadconditions[identity])
2275  ,&(wakeupmasterthreadlocks[identity]));
2276  }
2277  retval = wakeupmasterthread[identity];
2278  wakeupmasterthread[identity] = 0;
2279  UNLOCK(wakeupmasterthreadlocks[identity]);
2280  return(retval);
2281 }
2282 
2283 /*
2284  #] MasterWaitThread :
2285  #[ MasterWaitAll :
2286 */
2293 void MasterWaitAll()
2294 {
2295  LOCK(wakeupmasterlock);
2296  while ( topofavailables < numberofworkers ) {
2297  pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2298  }
2299  UNLOCK(wakeupmasterlock);
2300  return;
2301 }
2302 
2303 /*
2304  #] MasterWaitAll :
2305  #[ MasterWaitAllSortBots :
2306 */
2307 
2308 #ifdef WITHSORTBOTS
2309 
2315 void MasterWaitAllSortBots()
2316 {
2317  LOCK(wakeupsortbotlock);
2318  while ( topsortbotavailables < numberofsortbots ) {
2319  pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
2320  }
2321  UNLOCK(wakeupsortbotlock);
2322  return;
2323 }
2324 
2325 #endif
2326 
2327 /*
2328  #] MasterWaitAllSortBots :
2329  #[ MasterWaitAllBlocks :
2330 */
2337 void MasterWaitAllBlocks()
2338 {
2339  LOCK(wakeupmasterlock);
2340  while ( numberclaimed < numberofworkers ) {
2341  pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2342  }
2343  UNLOCK(wakeupmasterlock);
2344  return;
2345 }
2346 
2347 /*
2348  #] MasterWaitAllBlocks :
2349  #[ WakeupThread :
2350 */
2359 void WakeupThread(int identity, int signalnumber)
2360 {
2361  if ( signalnumber == 0 ) {
2362  MLOCK(ErrorMessageLock);
2363  MesPrint("Illegal wakeup signal for thread %d",identity);
2364  MUNLOCK(ErrorMessageLock);
2365  Terminate(-1);
2366  }
2367  LOCK(wakeuplocks[identity]);
2368  wakeup[identity] = signalnumber;
2369  pthread_cond_signal(&(wakeupconditions[identity]));
2370  UNLOCK(wakeuplocks[identity]);
2371 }
2372 
2373 /*
2374  #] WakeupThread :
2375  #[ WakeupMasterFromThread :
2376 */
2385 void WakeupMasterFromThread(int identity, int signalnumber)
2386 {
2387  if ( signalnumber == 0 ) {
2388  MLOCK(ErrorMessageLock);
2389  MesPrint("Illegal wakeup signal for master %d",identity);
2390  MUNLOCK(ErrorMessageLock);
2391  Terminate(-1);
2392  }
2393  LOCK(wakeupmasterthreadlocks[identity]);
2394  wakeupmasterthread[identity] = signalnumber;
2395  pthread_cond_signal(&(wakeupmasterthreadconditions[identity]));
2396  UNLOCK(wakeupmasterthreadlocks[identity]);
2397 }
2398 
2399 /*
2400  #] WakeupMasterFromThread :
2401  #[ SendOneBucket :
2402 */
2408 int SendOneBucket(int type)
2409 {
2410  ALLPRIVATES *B0 = AB[0];
2411  THREADBUCKET *thr = 0;
2412  int j, k, id;
2413  for ( j = 0; j < numthreadbuckets; j++ ) {
2414  if ( threadbuckets[j]->free == BUCKETFILLED ) {
2415  thr = threadbuckets[j];
2416  for ( k = j+1; k < numthreadbuckets; k++ )
2417  threadbuckets[k-1] = threadbuckets[k];
2418  threadbuckets[numthreadbuckets-1] = thr;
2419  break;
2420  }
2421  }
2422  AN0.ninterms++;
2423  while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2424 /*
2425  Prepare the thread. Give it the term and variables.
2426 */
2427  LoadOneThread(0,id,thr,0);
2428  thr->busy = BUCKETASSIGNED;
2429  thr->free = BUCKETINUSE;
2430  numberoffullbuckets--;
2431 /*
2432  And signal the thread to run.
2433  Form now on we may only interfere with this bucket
2434  1: after it has been marked BUCKETCOMINGFREE
2435  2: when thr->busy == BUCKETDOINGTERM and then only when protected by
2436  thr->lock. This would be for load balancing.
2437 */
2438  WakeupThread(id,type);
2439 /* AN0.ninterms += thr->ddterms; */
2440  return(0);
2441 }
2442 
2443 /*
2444  #] SendOneBucket :
2445  #[ InParallelProcessor :
2446 */
2466 int InParallelProcessor()
2467 {
2468  GETIDENTITY
2469  int i, id, retval = 0, num = 0;
2470  EXPRESSIONS e;
2471  if ( numberofworkers >= 2 ) {
2472  SetWorkerFiles();
2473  for ( i = 0; i < NumExpressions; i++ ) {
2474  e = Expressions+i;
2475  if ( e->partodo <= 0 ) continue;
2476  if ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION
2477  || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION
2478  || e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
2479  }
2480  else {
2481  e->partodo = 0;
2482  continue;
2483  }
2484  if ( e->counter == 0 ) { /* Expression with zero terms */
2485  e->partodo = 0;
2486  continue;
2487  }
2488 /*
2489  This expression should go to an idle worker
2490 */
2491  while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2492  LoadOneThread(0,id,0,-1);
2493  AB[id]->R.exprtodo = i;
2494  WakeupThread(id,DOONEEXPRESSION);
2495  num++;
2496  }
2497 /*
2498  Now we have to wait for all workers to finish
2499 */
2500  if ( num > 0 ) MasterWaitAll();
2501 
2502  if ( AC.CollectFun ) AR.DeferFlag = 0;
2503  }
2504  else {
2505  for ( i = 0; i < NumExpressions; i++ ) {
2506  Expressions[i].partodo = 0;
2507  }
2508  }
2509  return(retval);
2510 }
2511 
2512 /*
2513  #] InParallelProcessor :
2514  #[ ThreadsProcessor :
2515 */
2540 int ThreadsProcessor(EXPRESSIONS e, WORD LastExpression, WORD fromspectator)
2541 {
2542  ALLPRIVATES *B0 = AB[0], *B = B0;
2543  int id, oldgzipCompress, endofinput = 0, j, still, k, defcount = 0, bra = 0, first = 1;
2544  LONG dd = 0, ddd, thrbufsiz, thrbufsiz0, thrbufsiz2, numbucket = 0, numpasses;
2545  LONG num, i;
2546  WORD *oldworkpointer = AT0.WorkPointer, *tt, *ttco = 0, *t1 = 0, ter, *tstop = 0, *t2;
2547  THREADBUCKET *thr = 0;
2548  FILEHANDLE *oldoutfile = AR0.outfile;
2549  GETTERM GetTermP = &GetTerm;
2550  POSITION eonfile = AS.OldOnFile[e-Expressions];
2551  numberoffullbuckets = 0;
2552 /*
2553  Start up all threads. The lock needs to be around the whole loop
2554  to keep processes from terminating quickly and putting themselves
2555  in the list of available threads again.
2556 */
2557  AM.tracebackflag = 1;
2558 
2559  AS.sLevel = AR0.sLevel;
2560  LOCK(availabilitylock);
2561  topofavailables = 0;
2562  for ( id = 1; id <= numberofworkers; id++ ) {
2563  WakeupThread(id,STARTNEWEXPRESSION);
2564  }
2565  UNLOCK(availabilitylock);
2566  NewSort(BHEAD0);
2567  AN0.ninterms = 1;
2568 /*
2569  Now for redefine
2570 */
2571  if ( AC.numpfirstnum > 0 ) {
2572  for ( j = 0; j < AC.numpfirstnum; j++ ) {
2573  AC.inputnumbers[j] = -1;
2574  }
2575  }
2576  MasterWaitAll();
2577 /*
2578  Determine a reasonable bucketsize.
2579  This is based on the value of AC.ThreadBucketSize and the number
2580  of terms. We want at least 5 buckets per worker at the moment.
2581  Some research should show whether this is reasonable.
2582 
2583  The number of terms in the expression is in e->counter
2584 */
2585  thrbufsiz2 = thrbufsiz = AC.ThreadBucketSize-1;
2586  if ( ( e->counter / ( numberofworkers * 5 ) ) < thrbufsiz ) {
2587  thrbufsiz = e->counter / ( numberofworkers * 5 ) - 1;
2588  if ( thrbufsiz < 0 ) thrbufsiz = 0;
2589  }
2590  thrbufsiz0 = thrbufsiz;
2591  numpasses = 5; /* this is just for trying */
2592  thrbufsiz = thrbufsiz0 / (2 << numpasses);
2593 /*
2594  Mark all buckets as free and take the first.
2595 */
2596  for ( j = 0; j < numthreadbuckets; j++ )
2597  threadbuckets[j]->free = BUCKETFREE;
2598  thr = threadbuckets[0];
2599 /*
2600  #[ Whole brackets :
2601 
2602  First we look whether we have to work with entire brackets
2603  This is the case when there is a non-NULL address in e->bracketinfo.
2604  Of course we shouldn't have interference from a collect or keep statement.
2605 */
2606 #ifdef WHOLEBRACKETS
2607  if ( e->bracketinfo && AC.CollectFun == 0 && AR0.DeferFlag == 0 ) {
2608  FILEHANDLE *curfile;
2609  int didone = 0;
2610  LONG num, n;
2611  AN0.expr = e;
2612  for ( n = 0; n < e->bracketinfo->indexfill; n++ ) {
2613  num = TreatIndexEntry(B0,n);
2614  if ( num > 0 ) {
2615  didone = 1;
2616 /*
2617  This bracket can be sent off.
2618  1: Look for an empty bucket
2619 */
2620 ReTry:;
2621  for ( j = 0; j < numthreadbuckets; j++ ) {
2622  switch ( threadbuckets[j]->free ) {
2623  case BUCKETFREE:
2624  thr = threadbuckets[j];
2625  goto Found1;
2626  case BUCKETCOMINGFREE:
2627  thr = threadbuckets[j];
2628  thr->free = BUCKETFREE;
2629  for ( k = j+1; k < numthreadbuckets; k++ )
2630  threadbuckets[k-1] = threadbuckets[k];
2631  threadbuckets[numthreadbuckets-1] = thr;
2632  j--;
2633  break;
2634  default:
2635  break;
2636  }
2637  }
2638 Found1:;
2639  if ( j < numthreadbuckets ) {
2640 /*
2641  Found an empty bucket. Fill it.
2642 */
2643  thr->firstbracket = n;
2644  thr->lastbracket = n + num - 1;
2645  thr->type = BUCKETDOINGBRACKET;
2646  thr->free = BUCKETFILLED;
2647  thr->firstterm = AN0.ninterms;
2648  for ( j = n; j < n+num; j++ ) {
2649  AN0.ninterms += e->bracketinfo->indexbuffer[j].termsinbracket;
2650  }
2651  n += num-1;
2652  numberoffullbuckets++;
2653  if ( topofavailables > 0 ) {
2654  SendOneBucket(DOBRACKETS);
2655  }
2656  }
2657 /*
2658  All buckets are in use.
2659  Look/wait for an idle worker. Give it a bucket.
2660  After that, retry for a bucket
2661 */
2662  else {
2663  while ( topofavailables <= 0 ) {
2664  MasterWait();
2665  }
2666  SendOneBucket(DOBRACKETS);
2667  goto ReTry;
2668  }
2669  }
2670  }
2671  if ( didone ) {
2672 /*
2673  And now put the input back in the original position.
2674 */
2675  switch ( e->status ) {
2676  case UNHIDELEXPRESSION:
2677  case UNHIDEGEXPRESSION:
2678  case DROPHLEXPRESSION:
2679  case DROPHGEXPRESSION:
2680  case HIDDENLEXPRESSION:
2681  case HIDDENGEXPRESSION:
2682  curfile = AR0.hidefile;
2683  break;
2684  default:
2685  curfile = AR0.infile;
2686  break;
2687  }
2688  SetScratch(curfile,&eonfile);
2689  GetTerm(B0,AT0.WorkPointer);
2690 /*
2691  Now we point the GetTerm that is used to the one that is selective
2692 */
2693  GetTermP = &GetTerm2;
2694 /*
2695  Next wait till there is a bucket available and initialize thr to it.
2696 */
2697  for(;;) {
2698  for ( j = 0; j < numthreadbuckets; j++ ) {
2699  switch ( threadbuckets[j]->free ) {
2700  case BUCKETFREE:
2701  thr = threadbuckets[j];
2702  goto Found2;
2703  case BUCKETCOMINGFREE:
2704  thr = threadbuckets[j];
2705  thr->free = BUCKETFREE;
2706  for ( k = j+1; k < numthreadbuckets; k++ )
2707  threadbuckets[k-1] = threadbuckets[k];
2708  threadbuckets[numthreadbuckets-1] = thr;
2709  j--;
2710  break;
2711  default:
2712  break;
2713  }
2714  }
2715  while ( topofavailables <= 0 ) {
2716  MasterWait();
2717  }
2718  while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
2719  SendOneBucket(DOBRACKETS);
2720  }
2721  }
2722 Found2:;
2723  while ( numberoffullbuckets > 0 ) {
2724  while ( topofavailables <= 0 ) {
2725  MasterWait();
2726  }
2727  while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
2728  SendOneBucket(DOBRACKETS);
2729  }
2730  }
2731 /*
2732  Disable the 'warming up' with smaller buckets.
2733 
2734  numpasses = 0;
2735  thrbufsiz = thrbufsiz0;
2736 */
2737  AN0.lastinindex = -1;
2738  }
2739  MasterWaitAll();
2740  }
2741 #endif
2742 /*
2743  #] Whole brackets :
2744 
2745  Now the loop to start a bucket
2746 */
2747  for(;;) {
2748  if ( fromspectator ) {
2749  ter = GetFromSpectator(thr->threadbuffer,fromspectator-1);
2750  if ( ter == 0 ) fromspectator = 0;
2751  }
2752  else {
2753  ter = GetTermP(B0,thr->threadbuffer);
2754  }
2755  if ( ter < 0 ) break;
2756  if ( ter == 0 ) { endofinput = 1; goto Finalize; }
2757  dd = AN0.deferskipped;
2758  if ( AR0.DeferFlag ) {
2759  defcount = 0;
2760  thr->deferbuffer[defcount++] = AR0.DefPosition;
2761  ttco = thr->compressbuffer; t1 = AR0.CompressBuffer; j = *t1;
2762  NCOPY(ttco,t1,j);
2763  }
2764  else if ( first && ( AC.CollectFun == 0 ) ) { /* Brackets ? */
2765  first = 0;
2766  t1 = tstop = thr->threadbuffer;
2767  tstop += *tstop; tstop -= ABS(tstop[-1]);
2768  t1++;
2769  while ( t1 < tstop ) {
2770  if ( t1[0] == HAAKJE ) { bra = 1; break; }
2771  t1 += t1[1];
2772  }
2773  t1 = thr->threadbuffer;
2774  }
2775 /*
2776  Check whether we have a collect,function going. If so execute it.
2777 */
2778  if ( AC.CollectFun && *(thr->threadbuffer) < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
2779  if ( ( dd = GetMoreTerms(thr->threadbuffer) ) < 0 ) {
2780  LowerSortLevel(); goto ProcErr;
2781  }
2782  }
2783 /*
2784  Check whether we have a priority task:
2785 */
2786  if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2787 /*
2788  Now put more terms in the bucket. Position tt after the first term
2789 */
2790  tt = thr->threadbuffer; tt += *tt;
2791  thr->totnum = 1;
2792  thr->usenum = 0;
2793 /*
2794  Next we worry about the 'slow startup' in which we make the initial
2795  buckets smaller, so that we get all threads busy as soon as possible.
2796 */
2797  if ( numpasses > 0 ) {
2798  numbucket++;
2799  if ( numbucket >= numberofworkers ) {
2800  numbucket = 0;
2801  numpasses--;
2802  if ( numpasses == 0 ) thrbufsiz = thrbufsiz0;
2803  else thrbufsiz = thrbufsiz0 / (2 << numpasses);
2804  }
2805  thrbufsiz2 = thrbufsiz + thrbufsiz/5; /* for completing brackets */
2806  }
2807 /*
2808  we have already 1+dd terms
2809 */
2810  while ( ( dd < thrbufsiz ) &&
2811  ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer/((LONG)sizeof(WORD)) - 2 ) ) {
2812 /*
2813  First check:
2814 */
2815  if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2816 /*
2817  There is room in the bucket. Fill yet another term.
2818 */
2819  if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
2820  dd++;
2821  thr->totnum++;
2822  dd += AN0.deferskipped;
2823  if ( AR0.DeferFlag ) {
2824  thr->deferbuffer[defcount++] = AR0.DefPosition;
2825  t1 = AR0.CompressBuffer; j = *t1;
2826  NCOPY(ttco,t1,j);
2827  }
2828  if ( AC.CollectFun && *tt < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
2829  if ( ( ddd = GetMoreTerms(tt) ) < 0 ) {
2830  LowerSortLevel(); goto ProcErr;
2831  }
2832  dd += ddd;
2833  }
2834  t1 = tt;
2835  tt += *tt;
2836  }
2837 /*
2838  Check whether there are regular brackets and if we have no DeferFlag
2839  and no collect, we try to add more terms till we finish the current
2840  bracket. We should however not overdo it. Let us say: up to 20%
2841  more terms are allowed.
2842 */
2843  if ( bra ) {
2844  tstop = t1 + *t1; tstop -= ABS(tstop[-1]);
2845  t2 = t1+1;
2846  while ( t2 < tstop ) {
2847  if ( t2[0] == HAAKJE ) { break; }
2848  t2 += t2[1];
2849  }
2850  if ( t2[0] == HAAKJE ) {
2851  t2 += t2[1]; num = t2 - t1;
2852  while ( ( dd < thrbufsiz2 ) &&
2853  ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer - 2 ) ) {
2854 /*
2855  First check:
2856 */
2857  if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2858 /*
2859  There is room in the bucket. Fill yet another term.
2860 */
2861  if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
2862 /*
2863  Same bracket?
2864 */
2865  tstop = tt + *tt; tstop -= ABS(tstop[-1]);
2866  if ( tstop-tt < num ) { /* Different: abort */
2867  AR0.KeptInHold = 1;
2868  break;
2869  }
2870  for ( i = 1; i < num; i++ ) {
2871  if ( t1[i] != tt[i] ) break;
2872  }
2873  if ( i < num ) { /* Different: abort */
2874  AR0.KeptInHold = 1;
2875  break;
2876  }
2877 /*
2878  Same bracket. We need this term.
2879 */
2880  dd++;
2881  thr->totnum++;
2882  tt += *tt;
2883  }
2884  }
2885  }
2886  thr->ddterms = dd; /* total number of terms including keep brackets */
2887  thr->firstterm = AN0.ninterms;
2888  AN0.ninterms += dd;
2889  *tt = 0; /* mark end of bucket */
2890  thr->free = BUCKETFILLED;
2891  thr->type = BUCKETDOINGTERMS;
2892  numberoffullbuckets++;
2893  if ( topofavailables <= 0 && endofinput == 0 ) {
2894 /*
2895  Problem: topofavailables may already be > 0, but the
2896  thread has not yet gone into waiting. Can the signal get lost?
2897  How can we tell that a thread is waiting for a signal?
2898 
2899  All threads are busy. Try to load up another bucket.
2900  In the future we could be more sophisticated.
2901  At the moment we load a complete bucket which could be
2902  1000 terms or even more.
2903  In principle it is better to keep a full bucket ready
2904  and check after each term we put in the next bucket. That
2905  way we don't waste time of the workers.
2906 */
2907  for ( j = 0; j < numthreadbuckets; j++ ) {
2908  switch ( threadbuckets[j]->free ) {
2909  case BUCKETFREE:
2910  thr = threadbuckets[j];
2911  if ( !endofinput ) goto NextBucket;
2912 /*
2913  If we are at the end of the input we mark
2914  the free buckets in a special way. That way
2915  we don't keep running into them.
2916 */
2917  thr->free = BUCKETATEND;
2918  break;
2919  case BUCKETCOMINGFREE:
2920  thr = threadbuckets[j];
2921  thr->free = BUCKETFREE;
2922 /*
2923  Bucket has just been finished.
2924  Put at the end of the list. We don't want
2925  an early bucket to wait to be treated last.
2926 */
2927  for ( k = j+1; k < numthreadbuckets; k++ )
2928  threadbuckets[k-1] = threadbuckets[k];
2929  threadbuckets[numthreadbuckets-1] = thr;
2930  j--; /* we have to redo the same number j. */
2931  break;
2932  default:
2933  break;
2934  }
2935  }
2936 /*
2937  We have no free bucket or we are at the end.
2938  The only thing we can do now is wait for a worker to come free,
2939  provided there are still buckets to send.
2940 */
2941  }
2942 /*
2943  Look for the next bucket to send. There is at least one full bucket!
2944 */
2945  for ( j = 0; j < numthreadbuckets; j++ ) {
2946  if ( threadbuckets[j]->free == BUCKETFILLED ) {
2947  thr = threadbuckets[j];
2948  for ( k = j+1; k < numthreadbuckets; k++ )
2949  threadbuckets[k-1] = threadbuckets[k];
2950  threadbuckets[numthreadbuckets-1] = thr;
2951  break;
2952  }
2953  }
2954 /*
2955  Wait for a thread to become available
2956  The bucket we are going to use is in thr.
2957 */
2958 DoBucket:;
2959  AN0.ninterms++;
2960  while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2961 /*
2962  Prepare the thread. Give it the term and variables.
2963 */
2964  LoadOneThread(0,id,thr,0);
2965  LOCK(thr->lock);
2966  thr->busy = BUCKETASSIGNED;
2967  UNLOCK(thr->lock);
2968  thr->free = BUCKETINUSE;
2969  numberoffullbuckets--;
2970 /*
2971  And signal the thread to run.
2972  Form now on we may only interfere with this bucket
2973  1: after it has been marked BUCKETCOMINGFREE
2974  2: when thr->busy == BUCKETDOINGTERM and then only when protected by
2975  thr->lock. This would be for load balancing.
2976 */
2977  WakeupThread(id,LOWESTLEVELGENERATION);
2978 /* AN0.ninterms += thr->ddterms; */
2979 /*
2980  Now look whether there is another bucket filled and a worker available
2981 */
2982  if ( topofavailables > 0 ) { /* there is a worker */
2983  for ( j = 0; j < numthreadbuckets; j++ ) {
2984  if ( threadbuckets[j]->free == BUCKETFILLED ) {
2985  thr = threadbuckets[j];
2986  for ( k = j+1; k < numthreadbuckets; k++ )
2987  threadbuckets[k-1] = threadbuckets[k];
2988  threadbuckets[numthreadbuckets-1] = thr;
2989  goto DoBucket; /* and we found a bucket */
2990  }
2991  }
2992 /*
2993  no bucket is loaded but there is a thread available
2994  find a bucket to load. If there is none (all are USED or ATEND)
2995  we jump out of the loop.
2996 */
2997  for ( j = 0; j < numthreadbuckets; j++ ) {
2998  switch ( threadbuckets[j]->free ) {
2999  case BUCKETFREE:
3000  thr = threadbuckets[j];
3001  if ( !endofinput ) goto NextBucket;
3002  thr->free = BUCKETATEND;
3003  break;
3004  case BUCKETCOMINGFREE:
3005  thr = threadbuckets[j];
3006  if ( endofinput ) {
3007  thr->free = BUCKETATEND;
3008  }
3009  else {
3010  thr->free = BUCKETFREE;
3011  for ( k = j+1; k < numthreadbuckets; k++ )
3012  threadbuckets[k-1] = threadbuckets[k];
3013  threadbuckets[numthreadbuckets-1] = thr;
3014  j--;
3015  }
3016  break;
3017  default:
3018  break;
3019  }
3020  }
3021  if ( j >= numthreadbuckets ) break;
3022  }
3023  else {
3024 /*
3025  No worker available.
3026  Look for a bucket to load.
3027  Its number will be in "still"
3028 */
3029 Finalize:;
3030  still = -1;
3031  for ( j = 0; j < numthreadbuckets; j++ ) {
3032  switch ( threadbuckets[j]->free ) {
3033  case BUCKETFREE:
3034  thr = threadbuckets[j];
3035  if ( !endofinput ) goto NextBucket;
3036  thr->free = BUCKETATEND;
3037  break;
3038  case BUCKETCOMINGFREE:
3039  thr = threadbuckets[j];
3040  if ( endofinput ) thr->free = BUCKETATEND;
3041  else {
3042  thr->free = BUCKETFREE;
3043  for ( k = j+1; k < numthreadbuckets; k++ )
3044  threadbuckets[k-1] = threadbuckets[k];
3045  threadbuckets[numthreadbuckets-1] = thr;
3046  j--;
3047  }
3048  break;
3049  case BUCKETFILLED:
3050  if ( still < 0 ) still = j;
3051  break;
3052  default:
3053  break;
3054  }
3055  }
3056  if ( still < 0 ) {
3057 /*
3058  No buckets to be executed and no buckets FREE.
3059  We must be at the end. Break out of the loop.
3060 */
3061  break;
3062  }
3063  thr = threadbuckets[still];
3064  for ( k = still+1; k < numthreadbuckets; k++ )
3065  threadbuckets[k-1] = threadbuckets[k];
3066  threadbuckets[numthreadbuckets-1] = thr;
3067  goto DoBucket;
3068  }
3069 NextBucket:;
3070  }
3071 /*
3072  Now the stage one load balancing.
3073  If the load has been readjusted we have again filled buckets.
3074  In that case we jump back in the loop.
3075 
3076  Tricky point: when do the workers see the new value of AT.LoadBalancing?
3077  It should activate the locks on thr->busy
3078 */
3079  if ( AC.ThreadBalancing ) {
3080  for ( id = 1; id <= numberofworkers; id++ ) {
3081  AB[id]->T.LoadBalancing = 1;
3082  }
3083  if ( LoadReadjusted() ) goto Finalize;
3084  for ( id = 1; id <= numberofworkers; id++ ) {
3085  AB[id]->T.LoadBalancing = 0;
3086  }
3087  }
3088  if ( AC.ThreadBalancing ) {
3089 /*
3090  The AS.Balancing flag should have Generator look for
3091  free workers and apply the "buro" method.
3092 
3093  There is still a serious problem.
3094  When for instance a sum_, there may be space created in a local
3095  compiler buffer for a wildcard substitution or whatever.
3096  Compiler buffer execution scribble space.....
3097  This isn't copied along?
3098  Look up ebufnum. There are 12 places with AddRHS!
3099  Problem: one process alloces in ebuf. Then term is given to
3100  other process. It would like to use from this ebuf, but the sender
3101  finishes first and removes the ebuf (and/or overwrites it).
3102 
3103  Other problem: local $ variables aren't copied along.
3104 */
3105  AS.Balancing = 0;
3106  }
3107  MasterWaitAll();
3108  AS.Balancing = 0;
3109 /*
3110  When we deal with the last expression we can now remove the input
3111  scratch file. This saves potentially much disk space (up to 1/3)
3112 */
3113  if ( LastExpression ) {
3114  UpdateMaxSize();
3115  if ( AR0.infile->handle >= 0 ) {
3116  CloseFile(AR0.infile->handle);
3117  AR0.infile->handle = -1;
3118  remove(AR0.infile->name);
3119  PUTZERO(AR0.infile->POposition);
3120  AR0.infile->POfill = AR0.infile->POfull = AR0.infile->PObuffer;
3121  }
3122  }
3123 /*
3124  We order the threads to finish in the MasterMerge routine
3125  It will start with waiting for all threads to finish.
3126  One could make an administration in which threads that have
3127  finished can start already with the final sort but
3128  1: The load balancing should not make this super urgent
3129  2: It would definitely not be very compatible with the second
3130  stage load balancing.
3131 */
3132  oldgzipCompress = AR0.gzipCompress;
3133  AR0.gzipCompress = 0;
3134  if ( AR0.outtohide ) AR0.outfile = AR0.hidefile;
3135  if ( MasterMerge() < 0 ) {
3136  if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3137  AR0.gzipCompress = oldgzipCompress;
3138  goto ProcErr;
3139  }
3140  if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3141  AR0.gzipCompress = oldgzipCompress;
3142 /*
3143  Now wait for all threads to be ready to give them the cleaning up signal.
3144  With the new MasterMerge routine we can do the cleanup already automatically
3145  avoiding having to send these signals.
3146 */
3147  MasterWaitAll();
3148  AR0.sLevel--;
3149  for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
3150  if ( GetThread(id) > 0 ) WakeupThread(id,CLEANUPEXPRESSION);
3151  }
3152  e->numdummies = 0;
3153  for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
3154  if ( AB[id]->R.MaxDum - AM.IndDum > e->numdummies )
3155  e->numdummies = AB[id]->R.MaxDum - AM.IndDum;
3156  AR0.expchanged |= AB[id]->R.expchanged;
3157  }
3158 /*
3159  And wait for all to be clean.
3160 */
3161  MasterWaitAll();
3162  AT0.WorkPointer = oldworkpointer;
3163  return(0);
3164 ProcErr:;
3165  return(-1);
3166 }
3167 
3168 /*
3169  #] ThreadsProcessor :
3170  #[ LoadReadjusted :
3171 */
3190 int LoadReadjusted()
3191 {
3192  ALLPRIVATES *B0 = AB[0];
3193  THREADBUCKET *thr = 0, *thrtogo = 0;
3194  int numtogo, numfree, numbusy, n, nperbucket, extra, i, j, u, bus;
3195  LONG numinput;
3196  WORD *t1, *c1, *t2, *c2, *t3;
3197 /*
3198  Start with waiting for at least one free processor.
3199  We don't want the master competing for time when all are busy.
3200 */
3201  while ( topofavailables <= 0 ) MasterWait();
3202 /*
3203  Now look for the fullest bucket and make a list of free buckets
3204  The bad part is that most numbers can change at any moment.
3205 */
3206 restart:;
3207  numtogo = 0;
3208  numfree = 0;
3209  numbusy = 0;
3210  for ( j = 0; j < numthreadbuckets; j++ ) {
3211  thr = threadbuckets[j];
3212  if ( thr->free == BUCKETFREE || thr->free == BUCKETATEND
3213  || thr->free == BUCKETCOMINGFREE ) {
3214  freebuckets[numfree++] = thr;
3215  }
3216  else if ( thr->type != BUCKETDOINGTERMS ) {}
3217  else if ( thr->totnum > 1 ) { /* never steal from a bucket with one term */
3218  LOCK(thr->lock);
3219  bus = thr->busy;
3220  UNLOCK(thr->lock);
3221  if ( thr->free == BUCKETINUSE ) {
3222  n = thr->totnum-thr->usenum;
3223  if ( bus == BUCKETASSIGNED ) numbusy++;
3224  else if ( ( bus != BUCKETASSIGNED )
3225  && ( n > numtogo ) ) {
3226  numtogo = n;
3227  thrtogo = thr;
3228  }
3229  }
3230  else if ( bus == BUCKETTOBERELEASED
3231  && thr->free == BUCKETRELEASED ) {
3232  freebuckets[numfree++] = thr;
3233  thr->free = BUCKETATEND;
3234  LOCK(thr->lock);
3235  thr->busy = BUCKETPREPARINGTERM;
3236  UNLOCK(thr->lock);
3237  }
3238  }
3239  }
3240  if ( numfree == 0 ) return(0); /* serious problem */
3241  if ( numtogo > 0 ) { /* provisionally there is something to be stolen */
3242  thr = thrtogo;
3243 /*
3244  If the number has changed there is good progress.
3245  Maybe there is another thread that needs assistence.
3246  We start all over.
3247 */
3248  if ( thr->totnum-thr->usenum < numtogo ) goto restart;
3249 /*
3250  If the thread is in the term loading phace
3251  (thr->busy == BUCKETPREPARINGTERM) we better stay away from it.
3252  We wait now for the thread to be busy, and don't allow it
3253  now to drop out of this state till we are done here.
3254  This all depends on whether AT.LoadBalancing == 1 is seen by
3255  the thread.
3256 */
3257  LOCK(thr->lock);
3258  if ( thr->busy != BUCKETDOINGTERM ) {
3259  UNLOCK(thr->lock);
3260  goto restart;
3261  }
3262  if ( thr->totnum-thr->usenum < numtogo ) {
3263  UNLOCK(thr->lock);
3264  goto restart;
3265  }
3266  thr->free = BUCKETTERMINATED;
3267 /*
3268  The above will signal the thread we want to terminate.
3269  Next all effort goes into making sure the landing is soft.
3270  Unfortunately we don't want to wait for a signal, because the thread
3271  may be working for a long time on a single term.
3272 */
3273  if ( thr->usenum == thr->totnum ) {
3274 /*
3275  Terminated in the mean time or by now working on the
3276  last term. Try again.
3277 */
3278  thr->free = BUCKETATEND;
3279  UNLOCK(thr->lock);
3280  goto restart;
3281  }
3282  goto intercepted;
3283  }
3284 /* UNLOCK(thr->lock); */
3285  if ( numbusy > 0 ) return(1); /* Wait a bit.... */
3286  return(0);
3287 intercepted:;
3288 /*
3289  We intercepted one successfully. Now it becomes interesting. Action:
3290  1: determine how many terms per free bucket.
3291  2: find the first untreated term.
3292  3: put the terms in the free buckets.
3293 
3294  Remember: we have the lock to avoid interference from the thread
3295  that is being robbed.
3296 */
3297  numinput = thr->firstterm + thr->usenum;
3298  nperbucket = numtogo / numfree;
3299  extra = numtogo - nperbucket*numfree;
3300  if ( AR0.DeferFlag ) {
3301  t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
3302  for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
3303  t3 = t1;
3304  if ( extra > 0 ) {
3305  for ( i = 0; i < extra; i++ ) {
3306  thrtogo = freebuckets[i];
3307  t2 = thrtogo->threadbuffer;
3308  c2 = thrtogo->compressbuffer;
3309  thrtogo->free = BUCKETFILLED;
3310  thrtogo->type = BUCKETDOINGTERMS;
3311  thrtogo->totnum = nperbucket+1;
3312  thrtogo->ddterms = 0;
3313  thrtogo->usenum = 0;
3314  thrtogo->busy = BUCKETASSIGNED;
3315  thrtogo->firstterm = numinput;
3316  numinput += nperbucket+1;
3317  for ( n = 0; n <= nperbucket; n++ ) {
3318  j = *t1; NCOPY(t2,t1,j);
3319  j = *c1; NCOPY(c2,c1,j);
3320  thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
3321  }
3322  *t2 = *c2 = 0;
3323  }
3324  }
3325  if ( nperbucket > 0 ) {
3326  for ( i = extra; i < numfree; i++ ) {
3327  thrtogo = freebuckets[i];
3328  t2 = thrtogo->threadbuffer;
3329  c2 = thrtogo->compressbuffer;
3330  thrtogo->free = BUCKETFILLED;
3331  thrtogo->type = BUCKETDOINGTERMS;
3332  thrtogo->totnum = nperbucket;
3333  thrtogo->ddterms = 0;
3334  thrtogo->usenum = 0;
3335  thrtogo->busy = BUCKETASSIGNED;
3336  thrtogo->firstterm = numinput;
3337  numinput += nperbucket;
3338  for ( n = 0; n < nperbucket; n++ ) {
3339  j = *t1; NCOPY(t2,t1,j);
3340  j = *c1; NCOPY(c2,c1,j);
3341  thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
3342  }
3343  *t2 = *c2 = 0;
3344  }
3345  }
3346  }
3347  else {
3348  t1 = thr->threadbuffer;
3349  for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
3350  t3 = t1;
3351  if ( extra > 0 ) {
3352  for ( i = 0; i < extra; i++ ) {
3353  thrtogo = freebuckets[i];
3354  t2 = thrtogo->threadbuffer;
3355  thrtogo->free = BUCKETFILLED;
3356  thrtogo->type = BUCKETDOINGTERMS;
3357  thrtogo->totnum = nperbucket+1;
3358  thrtogo->ddterms = 0;
3359  thrtogo->usenum = 0;
3360  thrtogo->busy = BUCKETASSIGNED;
3361  thrtogo->firstterm = numinput;
3362  numinput += nperbucket+1;
3363  for ( n = 0; n <= nperbucket; n++ ) {
3364  j = *t1; NCOPY(t2,t1,j);
3365  }
3366  *t2 = 0;
3367  }
3368  }
3369  if ( nperbucket > 0 ) {
3370  for ( i = extra; i < numfree; i++ ) {
3371  thrtogo = freebuckets[i];
3372  t2 = thrtogo->threadbuffer;
3373  thrtogo->free = BUCKETFILLED;
3374  thrtogo->type = BUCKETDOINGTERMS;
3375  thrtogo->totnum = nperbucket;
3376  thrtogo->ddterms = 0;
3377  thrtogo->usenum = 0;
3378  thrtogo->busy = BUCKETASSIGNED;
3379  thrtogo->firstterm = numinput;
3380  numinput += nperbucket;
3381  for ( n = 0; n < nperbucket; n++ ) {
3382  j = *t1; NCOPY(t2,t1,j);
3383  }
3384  *t2 = 0;
3385  }
3386  }
3387  }
3388  *t3 = 0; /* This is some form of extra insurance */
3389  if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
3390  thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
3391  }
3392  UNLOCK(thr->lock);
3393  return(1);
3394 }
3395 
3396 /*
3397  #] LoadReadjusted :
3398  #[ SortStrategy :
3399 */
3432 /*
3433  #] SortStrategy :
3434  #[ PutToMaster :
3435 */
3458 int PutToMaster(PHEAD WORD *term)
3459 {
3460  int i,j,nexti,ret = 0;
3461  WORD *t, *fill, *top, zero = 0;
3462  if ( term == 0 ) { /* Mark the end of the expression */
3463  t = &zero; j = 1;
3464  }
3465  else {
3466  t = term; ret = j = *term;
3467  if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
3468  }
3469  i = AT.SB.FillBlock; /* The block we are working at */
3470  fill = AT.SB.MasterFill[i]; /* Where we are filling */
3471  top = AT.SB.MasterStop[i]; /* End of the block */
3472  while ( j > 0 ) {
3473  while ( j > 0 && fill < top ) {
3474  *fill++ = *t++; j--;
3475  }
3476  if ( j > 0 ) {
3477 /*
3478  We reached the end of the block.
3479  Get the next block and release this block.
3480  The order is important. This is why there should be at least
3481  4 blocks or deadlocks can occur.
3482 */
3483  nexti = i+1;
3484  if ( nexti > AT.SB.MasterNumBlocks ) {
3485  nexti = 1;
3486  }
3487  LOCK(AT.SB.MasterBlockLock[nexti]);
3488  UNLOCK(AT.SB.MasterBlockLock[i]);
3489  AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
3490  AT.SB.FillBlock = i = nexti;
3491  fill = AT.SB.MasterStart[i];
3492  top = AT.SB.MasterStop[i];
3493  }
3494  }
3495  AT.SB.MasterFill[i] = fill;
3496  return(ret);
3497 }
3498 
3499 /*
3500  #] PutToMaster :
3501  #[ SortBotOut :
3502 */
3503 
3504 #ifdef WITHSORTBOTS
3505 
3514 int
3515 SortBotOut(PHEAD WORD *term)
3516 {
3517  WORD im;
3518 
3519  if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
3520 
3521  if ( term == 0 ) {
3522  if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
3523  ADDPOS(AT.SS->SizeInFile[0],1);
3524  return(0);
3525  }
3526  else {
3527  numberofterms++;
3528  if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
3529  MLOCK(ErrorMessageLock);
3530  MesPrint("Called from MasterMerge/SortBotOut");
3531  MUNLOCK(ErrorMessageLock);
3532  return(-1);
3533  }
3534  ADDPOS(AT.SS->SizeInFile[0],im);
3535  return(im);
3536  }
3537 }
3538 
3539 #endif
3540 
3541 /*
3542  #] SortBotOut :
3543  #[ MasterMerge :
3544 */
3562 int MasterMerge()
3563 {
3564  ALLPRIVATES *B0 = AB[0], *B = 0;
3565  SORTING *S = AT0.SS;
3566  WORD **poin, **poin2, ul, k, i, im, *m1, j;
3567  WORD lpat, mpat, level, l1, l2, r1, r2, r3, c;
3568  WORD *m2, *m3, r31, r33, ki, *rr;
3569  UWORD *coef;
3570  POSITION position;
3571  FILEHANDLE *fin, *fout;
3572 #ifdef WITHSORTBOTS
3573  if ( numberofworkers > 2 ) return(SortBotMasterMerge());
3574 #endif
3575  fin = &S->file;
3576  if ( AR0.PolyFun == 0 ) { S->PolyFlag = 0; }
3577  else if ( AR0.PolyFunType == 1 ) { S->PolyFlag = 1; }
3578  else if ( AR0.PolyFunType == 2 ) {
3579  if ( AR0.PolyFunExp == 2
3580  || AR0.PolyFunExp == 3 ) S->PolyFlag = 1;
3581  else S->PolyFlag = 2;
3582  }
3583  S->TermsLeft = 0;
3584  coef = AN0.SoScratC;
3585  poin = S->poina; poin2 = S->poin2a;
3586  rr = AR0.CompressPointer;
3587  *rr = 0;
3588 /*
3589  #[ Setup :
3590 */
3591  S->inNum = numberofthreads;
3592  fout = AR0.outfile;
3593 /*
3594  Load the patches. The threads have to finish their sort first.
3595 */
3596  S->lPatch = S->inNum - 1;
3597 /*
3598  Claim all zero blocks. We need them anyway.
3599  In principle the workers should never get into these.
3600  We also claim all last blocks. This is a safety procedure that
3601  should prevent the workers from working their way around the clock
3602  before the master gets started again.
3603 */
3604  AS.MasterSort = 1;
3605  numberclaimed = 0;
3606  for ( i = 1; i <= S->lPatch; i++ ) {
3607  B = AB[i];
3608  LOCK(AT.SB.MasterBlockLock[0]);
3609  LOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
3610  }
3611 /*
3612  Now wake up the threads and have them start their final sorting.
3613  They should start with claiming their block and the master is
3614  not allowed to continue until that has been done.
3615  This waiting of the master will be done below in MasterWaitAllBlocks
3616 */
3617  for ( i = 0; i < S->lPatch; i++ ) {
3618  GetThread(i+1);
3619  WakeupThread(i+1,FINISHEXPRESSION);
3620  }
3621 /*
3622  Prepare the output file.
3623 */
3624  if ( fout->handle >= 0 ) {
3625  PUTZERO(position);
3626  SeekFile(fout->handle,&position,SEEK_END);
3627  ADDPOS(position,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
3628  }
3629  else {
3630  SETBASEPOSITION(position,(fout->POfill-fout->PObuffer)*sizeof(WORD));
3631  }
3632 /*
3633  Wait for all threads to finish loading their first block.
3634 */
3635  MasterWaitAllBlocks();
3636 /*
3637  Claim all first blocks.
3638  We don't release the last blocks.
3639  The strategy is that we always keep the previous block.
3640  In principle it looks like it isn't needed for the last block but
3641  actually it is to keep the front from overrunning the tail when writing.
3642 */
3643  for ( i = 1; i <= S->lPatch; i++ ) {
3644  B = AB[i];
3645  LOCK(AT.SB.MasterBlockLock[1]);
3646  AT.SB.MasterBlock = 1;
3647  }
3648 /*
3649  #] Setup :
3650 
3651  Now construct the tree:
3652 */
3653  lpat = 1;
3654  do { lpat <<= 1; } while ( lpat < S->lPatch );
3655  mpat = ( lpat >> 1 ) - 1;
3656  k = lpat - S->lPatch;
3657 /*
3658  k is the number of empty places in the tree. they will
3659  be at the even positions from 2 to 2*k
3660 */
3661  for ( i = 1; i < lpat; i++ ) { S->tree[i] = -1; }
3662  for ( i = 1; i <= k; i++ ) {
3663  im = ( i << 1 ) - 1;
3664  poin[im] = AB[i]->T.SB.MasterStart[AB[i]->T.SB.MasterBlock];
3665  poin2[im] = poin[im] + *(poin[im]);
3666  S->used[i] = im;
3667  S->ktoi[im] = i-1;
3668  S->tree[mpat+i] = 0;
3669  poin[im-1] = poin2[im-1] = 0;
3670  }
3671  for ( i = (k<<1)+1; i <= lpat; i++ ) {
3672  S->used[i-k] = i;
3673  S->ktoi[i] = i-k-1;
3674  poin[i] = AB[i-k]->T.SB.MasterStart[AB[i-k]->T.SB.MasterBlock];
3675  poin2[i] = poin[i] + *(poin[i]);
3676  }
3677 /*
3678  the array poin tells the position of the i-th element of the S->tree
3679  'S->used' is a stack with the S->tree elements that need to be entered
3680  into the S->tree. at the beginning this is S->lPatch. during the
3681  sort there will be only very few elements.
3682  poin2 is the next value of poin. it has to be determined
3683  before the comparisons as the position or the size of the
3684  term indicated by poin may change.
3685  S->ktoi translates a S->tree element back to its stream number.
3686 
3687  start the sort
3688 */
3689  level = S->lPatch;
3690 /*
3691  introduce one term
3692 */
3693 OneTerm:
3694  k = S->used[level];
3695  i = k + lpat - 1;
3696  if ( !*(poin[k]) ) {
3697  do { if ( !( i >>= 1 ) ) goto EndOfMerge; } while ( !S->tree[i] );
3698  if ( S->tree[i] == -1 ) {
3699  S->tree[i] = 0;
3700  level--;
3701  goto OneTerm;
3702  }
3703  k = S->tree[i];
3704  S->used[level] = k;
3705  S->tree[i] = 0;
3706  }
3707 /*
3708  move terms down the tree
3709 */
3710  while ( i >>= 1 ) {
3711  if ( S->tree[i] > 0 ) {
3712  if ( ( c = CompareTerms(B0,poin[S->tree[i]],poin[k],(WORD)0) ) > 0 ) {
3713 /*
3714  S->tree[i] is the smaller. Exchange and go on.
3715 */
3716  S->used[level] = S->tree[i];
3717  S->tree[i] = k;
3718  k = S->used[level];
3719  }
3720  else if ( !c ) { /* Terms are equal */
3721 /*
3722  S->TermsLeft--;
3723  Here the terms are equal and their coefficients
3724  have to be added.
3725 */
3726  l1 = *( m1 = poin[S->tree[i]] );
3727  l2 = *( m2 = poin[k] );
3728  if ( S->PolyWise ) { /* Here we work with PolyFun */
3729  WORD *tt1, *w;
3730  tt1 = m1;
3731  m1 += S->PolyWise;
3732  m2 += S->PolyWise;
3733  if ( S->PolyFlag == 2 ) {
3734  w = poly_ratfun_add(B0,m1,m2);
3735  if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
3736  MLOCK(ErrorMessageLock);
3737  MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
3738  MUNLOCK(ErrorMessageLock);
3739  Terminate(-1);
3740  }
3741  AT0.WorkPointer = w;
3742  if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
3743  goto cancelled;
3744  }
3745  }
3746  else {
3747  w = AT0.WorkPointer;
3748  if ( w + m1[1] + m2[1] > AT0.WorkTop ) {
3749  MLOCK(ErrorMessageLock);
3750  MesPrint("MasterMerge: A WorkSpace of %10l is too small",AM.WorkSize);
3751  MUNLOCK(ErrorMessageLock);
3752  Terminate(-1);
3753  }
3754  AddArgs(B0,m1,m2,w);
3755  }
3756  r1 = w[1];
3757  if ( r1 <= FUNHEAD
3758  || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
3759  { goto cancelled; }
3760  if ( r1 == m1[1] ) {
3761  NCOPY(m1,w,r1);
3762  }
3763  else if ( r1 < m1[1] ) {
3764  r2 = m1[1] - r1;
3765  m2 = w + r1;
3766  m1 += m1[1];
3767  while ( --r1 >= 0 ) *--m1 = *--m2;
3768  m2 = m1 - r2;
3769  r1 = S->PolyWise;
3770  while ( --r1 >= 0 ) *--m1 = *--m2;
3771  *m1 -= r2;
3772  poin[S->tree[i]] = m1;
3773  }
3774  else {
3775  r2 = r1 - m1[1];
3776  m2 = tt1 - r2;
3777  r1 = S->PolyWise;
3778  m1 = tt1;
3779  *m1 += r2;
3780  poin[S->tree[i]] = m2;
3781  NCOPY(m2,m1,r1);
3782  r1 = w[1];
3783  NCOPY(m2,w,r1);
3784  }
3785  }
3786  else {
3787  r1 = *( m1 += l1 - 1 );
3788  m1 -= ABS(r1) - 1;
3789  r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
3790  r2 = *( m2 += l2 - 1 );
3791  m2 -= ABS(r2) - 1;
3792  r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
3793 
3794  if ( AddRat(B0,(UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
3795  MLOCK(ErrorMessageLock);
3796  MesCall("MasterMerge");
3797  MUNLOCK(ErrorMessageLock);
3798  SETERROR(-1)
3799  }
3800 
3801  if ( AN.ncmod != 0 ) {
3802  if ( ( AC.modmode & POSNEG ) != 0 ) {
3803  NormalModulus(coef,&r3);
3804  }
3805  else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
3806  WORD ii;
3807  SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
3808  coef[r3] = 1;
3809  for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
3810  }
3811  }
3812  r3 <<= 1;
3813  r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
3814  if ( r3 < 0 ) r3 = -r3;
3815  if ( r1 < 0 ) r1 = -r1;
3816  r1 <<= 1;
3817  r31 = r3 - r1;
3818  if ( !r3 ) { /* Terms cancel */
3819 cancelled:
3820  ul = S->used[level] = S->tree[i];
3821  S->tree[i] = -1;
3822 /*
3823  We skip to the next term in stream ul
3824 */
3825  im = *poin2[ul];
3826  poin[ul] = poin2[ul];
3827  ki = S->ktoi[ul];
3828  if ( (poin[ul] + im + COMPINC) >=
3829  AB[ki+1]->T.SB.MasterStop[AB[ki+1]->T.SB.MasterBlock]
3830  && im > 0 ) {
3831 /*
3832  We made it to the end of the block. We have to
3833  release the previous block and claim the next.
3834 */
3835  B = AB[ki+1];
3836  i = AT.SB.MasterBlock;
3837  if ( i == 1 ) {
3838  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
3839  }
3840  else {
3841  UNLOCK(AT.SB.MasterBlockLock[i-1]);
3842  }
3843  if ( i == AT.SB.MasterNumBlocks ) {
3844 /*
3845  Move the remainder down into block 0
3846 */
3847  WORD *from, *to;
3848  to = AT.SB.MasterStart[1];
3849  from = AT.SB.MasterStop[i];
3850  while ( from > poin[ul] ) *--to = *--from;
3851  poin[ul] = to;
3852  i = 1;
3853  }
3854  else { i++; }
3855  LOCK(AT.SB.MasterBlockLock[i]);
3856  AT.SB.MasterBlock = i;
3857  poin2[ul] = poin[ul] + im;
3858  }
3859  else {
3860  poin2[ul] += im;
3861  }
3862  S->used[++level] = k;
3863 /* S->TermsLeft--; */
3864  }
3865  else if ( !r31 ) { /* copy coef into term1 */
3866  goto CopCof2;
3867  }
3868  else if ( r31 < 0 ) { /* copy coef into term1
3869  and adjust the length of term1 */
3870  goto CopCoef;
3871  }
3872  else {
3873 /*
3874  this is the dreaded calamity.
3875  is there enough space?
3876 */
3877  if( (poin[S->tree[i]]+l1+r31) >= poin2[S->tree[i]] ) {
3878 /*
3879  no space! now the special trick for which
3880  we left 2*maxlng spaces open at the beginning
3881  of each patch.
3882 */
3883  if ( (l1 + r31)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
3884  MLOCK(ErrorMessageLock);
3885  MesPrint("MasterMerge: Coefficient overflow during sort");
3886  MUNLOCK(ErrorMessageLock);
3887  goto ReturnError;
3888  }
3889  m2 = poin[S->tree[i]];
3890  m3 = ( poin[S->tree[i]] -= r31 );
3891  do { *m3++ = *m2++; } while ( m2 < m1 );
3892  m1 = m3;
3893  }
3894 CopCoef:
3895  *(poin[S->tree[i]]) += r31;
3896 CopCof2:
3897  m2 = (WORD *)coef; im = r3;
3898  NCOPY(m1,m2,im);
3899  *m1 = r33;
3900  }
3901  }
3902 /*
3903  Now skip to the next term in stream k.
3904 */
3905 NextTerm:
3906  im = poin2[k][0];
3907  poin[k] = poin2[k];
3908  ki = S->ktoi[k];
3909  if ( (poin[k] + im + COMPINC) >=
3910  AB[ki+1]->T.SB.MasterStop[AB[ki+1]->T.SB.MasterBlock]
3911  && im > 0 ) {
3912 /*
3913  We made it to the end of the block. We have to
3914  release the previous block and claim the next.
3915 */
3916  B = AB[ki+1];
3917  i = AT.SB.MasterBlock;
3918  if ( i == 1 ) {
3919  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
3920  }
3921  else {
3922  UNLOCK(AT.SB.MasterBlockLock[i-1]);
3923  }
3924  if ( i == AT.SB.MasterNumBlocks ) {
3925 /*
3926  Move the remainder down into block 0
3927 */
3928  WORD *from, *to;
3929  to = AT.SB.MasterStart[1];
3930  from = AT.SB.MasterStop[i];
3931  while ( from > poin[k] ) *--to = *--from;
3932  poin[k] = to;
3933  i = 1;
3934  }
3935  else { i++; }
3936  LOCK(AT.SB.MasterBlockLock[i]);
3937  AT.SB.MasterBlock = i;
3938  poin2[k] = poin[k] + im;
3939  }
3940  else {
3941  poin2[k] += im;
3942  }
3943  goto OneTerm;
3944  }
3945  }
3946  else if ( S->tree[i] < 0 ) {
3947  S->tree[i] = k;
3948  level--;
3949  goto OneTerm;
3950  }
3951  }
3952 /*
3953  found the smallest in the set. indicated by k.
3954  write to its destination.
3955 */
3956  S->TermsLeft++;
3957  if ( ( im = PutOut(B0,poin[k],&position,fout,1) ) < 0 ) {
3958  MLOCK(ErrorMessageLock);
3959  MesPrint("Called from MasterMerge with k = %d (stream %d)",k,S->ktoi[k]);
3960  MUNLOCK(ErrorMessageLock);
3961  goto ReturnError;
3962  }
3963  ADDPOS(S->SizeInFile[0],im);
3964  goto NextTerm;
3965 EndOfMerge:
3966  if ( FlushOut(&position,fout,1) ) goto ReturnError;
3967  ADDPOS(S->SizeInFile[0],1);
3968  CloseFile(fin->handle);
3969  remove(fin->name);
3970  fin->handle = -1;
3971  position = S->SizeInFile[0];
3972  MULPOS(position,sizeof(WORD));
3973  S->GenTerms = 0;
3974  for ( j = 1; j <= numberofworkers; j++ ) {
3975  S->GenTerms += AB[j]->T.SS->GenTerms;
3976  }
3977  WriteStats(&position,2);
3978  Expressions[AR0.CurExpr].counter = S->TermsLeft;
3979  Expressions[AR0.CurExpr].size = position;
3980 /*
3981  Release all locks
3982 */
3983  for ( i = 1; i <= S->lPatch; i++ ) {
3984  B = AB[i];
3985  UNLOCK(AT.SB.MasterBlockLock[0]);
3986  if ( AT.SB.MasterBlock == 1 ) {
3987  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
3988  }
3989  else {
3990  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock-1]);
3991  }
3992  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock]);
3993  }
3994  AS.MasterSort = 0;
3995  return(0);
3996 ReturnError:
3997  for ( i = 1; i <= S->lPatch; i++ ) {
3998  B = AB[i];
3999  UNLOCK(AT.SB.MasterBlockLock[0]);
4000  if ( AT.SB.MasterBlock == 1 ) {
4001  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
4002  }
4003  else {
4004  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock-1]);
4005  }
4006  UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock]);
4007  }
4008  AS.MasterSort = 0;
4009  return(-1);
4010 }
4011 
4012 /*
4013  #] MasterMerge :
4014  #[ SortBotMasterMerge :
4015 */
4016 
4017 #ifdef WITHSORTBOTS
4018 
4034 int SortBotMasterMerge()
4035 {
4036  FILEHANDLE *fin, *fout;
4037  ALLPRIVATES *B = AB[0], *BB;
4038  POSITION position;
4039  SORTING *S = AT.SS;
4040  int i, j;
4041 /*
4042  Get the sortbots get to claim their writing blocks.
4043  We have to wait till all have been claimed because they also have to
4044  claim the last writing blocks of the workers to prevent the head of
4045  the circular buffer to overrun the tail.
4046 
4047  Before waiting we can do some needed initializations.
4048  Also the master has to claim the last writing blocks of its input.
4049 */
4050  topsortbotavailables = 0;
4051  for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
4052  WakeupThread(i,INISORTBOT);
4053  }
4054 
4055  AS.MasterSort = 1;
4056  fout = AR.outfile;
4057  numberofterms = 0;
4058  AR.CompressPointer[0] = 0;
4059  numberclaimed = 0;
4060  BB = AB[AT.SortBotIn1];
4061  LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
4062  BB = AB[AT.SortBotIn2];
4063  LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
4064 
4065  MasterWaitAllSortBots();
4066 /*
4067  Now we can start up the workers. They will claim their writing blocks.
4068  Here the master will wait till all writing blocks have been claimed.
4069 */
4070  for ( i = 1; i <= numberofworkers; i++ ) {
4071  j = GetThread(i);
4072  WakeupThread(i,FINISHEXPRESSION);
4073  }
4074 /*
4075  Prepare the output file in the mean time.
4076 */
4077  if ( fout->handle >= 0 ) {
4078  PUTZERO(SortBotPosition);
4079  SeekFile(fout->handle,&SortBotPosition,SEEK_END);
4080  ADDPOS(SortBotPosition,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
4081  }
4082  else {
4083  SETBASEPOSITION(SortBotPosition,(fout->POfill-fout->PObuffer)*sizeof(WORD));
4084  }
4085  MasterWaitAllBlocks();
4086 /*
4087  Now we can start the sortbots after which the master goes in
4088  sortbot mode to do its part of the job (the very final merge and
4089  the writing to output file).
4090 */
4091  topsortbotavailables = 0;
4092  for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
4093  WakeupThread(i,RUNSORTBOT);
4094  }
4095  if ( SortBotMerge(BHEAD0) ) {
4096  MLOCK(ErrorMessageLock);
4097  MesPrint("Called from SortBotMasterMerge");
4098  MUNLOCK(ErrorMessageLock);
4099  AS.MasterSort = 0;
4100  return(-1);
4101  }
4102 /*
4103  And next the cleanup
4104 */
4105  if ( S->file.handle >= 0 )
4106  {
4107  fin = &S->file;
4108  CloseFile(fin->handle);
4109  remove(fin->name);
4110  fin->handle = -1;
4111  }
4112  position = S->SizeInFile[0];
4113  MULPOS(position,sizeof(WORD));
4114  S->GenTerms = 0;
4115  for ( j = 1; j <= numberofworkers; j++ ) {
4116  S->GenTerms += AB[j]->T.SS->GenTerms;
4117  }
4118  S->TermsLeft = numberofterms;
4119  WriteStats(&position,2);
4120  Expressions[AR.CurExpr].counter = S->TermsLeft;
4121  Expressions[AR.CurExpr].size = position;
4122  AS.MasterSort = 0;
4123 /*
4124  The next statement is to prevent one of the sortbots not having
4125  completely cleaned up before the next module starts.
4126  If this statement is omitted every once in a while one of the sortbots
4127  is still running when the next expression starts and misses its
4128  initialization. The result is usually disastrous.
4129 */
4130  MasterWaitAllSortBots();
4131 
4132  return(0);
4133 }
4134 
4135 #endif
4136 
4137 /*
4138  #] SortBotMasterMerge :
4139  #[ SortBotMerge :
4140 */
4141 
4142 #ifdef WITHSORTBOTS
4143 
4149 int SortBotMerge(PHEAD0)
4150 {
4151  GETBIDENTITY
4152  ALLPRIVATES *Bin1 = AB[AT.SortBotIn1],*Bin2 = AB[AT.SortBotIn2];
4153  WORD *term1, *term2, *next, *wp;
4154  int blin1, blin2; /* Current block numbers */
4155  int error = 0;
4156  WORD l1, l2, *m1, *m2, *w, r1, r2, r3, r33, r31, *tt1, ii;
4157  WORD *to, *from, im, c;
4158  UWORD *coef;
4159  SORTING *S = AT.SS;
4160 /*
4161  Set the pointers to the input terms and the output space
4162 */
4163  coef = AN.SoScratC;
4164  blin1 = 1;
4165  blin2 = 1;
4166  if ( AT.identity == 0 ) {
4167  wp = AT.WorkPointer;
4168  }
4169  else {
4170  wp = AT.WorkPointer = AT.WorkSpace;
4171  }
4172 /*
4173  Get the locks for reading the input
4174  This means that we can start once these locks have been cleared
4175  which means that there will be input.
4176 */
4177  LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4178  LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4179 
4180  term1 = Bin1->T.SB.MasterStart[blin1];
4181  term2 = Bin2->T.SB.MasterStart[blin2];
4182  AT.SB.FillBlock = 1;
4183 /*
4184  Now the main loop. Keep going until one of the two hits the end.
4185 */
4186  while ( *term1 && *term2 ) {
4187  if ( ( c = CompareTerms(BHEAD term1,term2,(WORD)0) ) > 0 ) {
4188 /*
4189  #[ One is smallest :
4190 */
4191  if ( SortBotOut(BHEAD term1) < 0 ) {
4192  MLOCK(ErrorMessageLock);
4193  MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4194  MUNLOCK(ErrorMessageLock);
4195  error = -1;
4196  goto ReturnError;
4197  }
4198  im = *term1;
4199  next = term1 + im;
4200  if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
4201  next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
4202  if ( blin1 == 1 ) {
4203  UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4204  }
4205  else {
4206  UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4207  }
4208  if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4209 /*
4210  Move the remainder down into block 0
4211 */
4212  to = Bin1->T.SB.MasterStart[1];
4213  from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
4214  while ( from > next ) *--to = *--from;
4215  next = to;
4216  blin1 = 1;
4217  }
4218  else {
4219  blin1++;
4220  }
4221  LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4222  Bin1->T.SB.MasterBlock = blin1;
4223  }
4224  term1 = next;
4225 /*
4226  #] One is smallest :
4227 */
4228  }
4229  else if ( c < 0 ) {
4230 /*
4231  #[ Two is smallest :
4232 */
4233  if ( SortBotOut(BHEAD term2) < 0 ) {
4234  MLOCK(ErrorMessageLock);
4235  MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4236  MUNLOCK(ErrorMessageLock);
4237  error = -1;
4238  goto ReturnError;
4239  }
4240 next2: im = *term2;
4241  next = term2 + im;
4242  if ( next >= Bin2->T.SB.MasterStop[blin2] || ( *next
4243  && next+*next+COMPINC > Bin2->T.SB.MasterStop[blin2] ) ) {
4244  if ( blin2 == 1 ) {
4245  UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4246  }
4247  else {
4248  UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4249  }
4250  if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4251 /*
4252  Move the remainder down into block 0
4253 */
4254  to = Bin2->T.SB.MasterStart[1];
4255  from = Bin2->T.SB.MasterStop[Bin2->T.SB.MasterNumBlocks];
4256  while ( from > next ) *--to = *--from;
4257  next = to;
4258  blin2 = 1;
4259  }
4260  else {
4261  blin2++;
4262  }
4263  LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4264  Bin2->T.SB.MasterBlock = blin2;
4265  }
4266  term2 = next;
4267 /*
4268  #] Two is smallest :
4269 */
4270  }
4271  else {
4272 /*
4273  #[ Equal :
4274 */
4275  l1 = *( m1 = term1 );
4276  l2 = *( m2 = term2 );
4277  if ( S->PolyWise ) { /* Here we work with PolyFun */
4278  tt1 = m1;
4279  m1 += S->PolyWise;
4280  m2 += S->PolyWise;
4281  if ( S->PolyFlag == 2 ) {
4282  AT.WorkPointer = wp;
4283  w = poly_ratfun_add(BHEAD m1,m2);
4284  if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
4285  MLOCK(ErrorMessageLock);
4286  MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
4287  MUNLOCK(ErrorMessageLock);
4288  Terminate(-1);
4289  }
4290  AT.WorkPointer = wp;
4291  if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
4292  goto cancelled;
4293  }
4294  }
4295  else {
4296  w = wp;
4297  if ( w + m1[1] + m2[1] > AT.WorkTop ) {
4298  MLOCK(ErrorMessageLock);
4299  MesPrint("SortBotMerge(%d): A Maxtermsize of %10l is too small",
4300  AT.identity,AM.MaxTer/sizeof(WORD));
4301  MesPrint("m1[1] = %d, m2[1] = %d, Space = %l",m1[1],m2[1],(LONG)(AT.WorkTop-wp));
4302  PrintTerm(term1,"term1");
4303  PrintTerm(term2,"term2");
4304  MesPrint("PolyWise = %d",S->PolyWise);
4305  MUNLOCK(ErrorMessageLock);
4306  Terminate(-1);
4307  }
4308  AddArgs(BHEAD m1,m2,w);
4309  }
4310  r1 = w[1];
4311  if ( r1 <= FUNHEAD
4312  || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
4313  { goto cancelled; }
4314  if ( r1 == m1[1] ) {
4315  NCOPY(m1,w,r1);
4316  }
4317  else if ( r1 < m1[1] ) {
4318  r2 = m1[1] - r1;
4319  m2 = w + r1;
4320  m1 += m1[1];
4321  while ( --r1 >= 0 ) *--m1 = *--m2;
4322  m2 = m1 - r2;
4323  r1 = S->PolyWise;
4324  while ( --r1 >= 0 ) *--m1 = *--m2;
4325  *m1 -= r2;
4326  term1 = m1;
4327  }
4328  else {
4329  r2 = r1 - m1[1];
4330  m2 = tt1 - r2;
4331  r1 = S->PolyWise;
4332  m1 = tt1;
4333  *m1 += r2;
4334  term1 = m2;
4335  NCOPY(m2,m1,r1);
4336  r1 = w[1];
4337  NCOPY(m2,w,r1);
4338  }
4339  }
4340  else {
4341  r1 = *( m1 += l1 - 1 );
4342  m1 -= ABS(r1) - 1;
4343  r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
4344  r2 = *( m2 += l2 - 1 );
4345  m2 -= ABS(r2) - 1;
4346  r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
4347 
4348  if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
4349  MLOCK(ErrorMessageLock);
4350  MesCall("SortBotMerge");
4351  MUNLOCK(ErrorMessageLock);
4352  SETERROR(-1)
4353  }
4354 
4355  if ( AN.ncmod != 0 ) {
4356  if ( ( AC.modmode & POSNEG ) != 0 ) {
4357  NormalModulus(coef,&r3);
4358  }
4359  else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
4360  SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
4361  coef[r3] = 1;
4362  for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
4363  }
4364  }
4365  if ( !r3 ) { goto cancelled; }
4366  r3 <<= 1;
4367  r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
4368  if ( r3 < 0 ) r3 = -r3;
4369  if ( r1 < 0 ) r1 = -r1;
4370  r1 <<= 1;
4371  r31 = r3 - r1;
4372  if ( !r31 ) { /* copy coef into term1 */
4373  m2 = (WORD *)coef; im = r3;
4374  NCOPY(m1,m2,im);
4375  *m1 = r33;
4376  }
4377 /*
4378  else if ( r31 < 0 ) {
4379  *term1 += r31;
4380  m2 = (WORD *)coef; im = r3;
4381  NCOPY(m1,m2,im);
4382  *m1 = r33;
4383  }
4384 */
4385  else {
4386  to = wp; from = term1;
4387  while ( from < m1 ) *to++ = *from++;
4388  from = (WORD *)coef; im = r3;
4389  NCOPY(to,from,im);
4390  *to++ = r33;
4391  wp[0] = to - wp;
4392  if ( SortBotOut(BHEAD wp) < 0 ) {
4393  MLOCK(ErrorMessageLock);
4394  MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4395  MUNLOCK(ErrorMessageLock);
4396  error = -1;
4397  goto ReturnError;
4398  }
4399  goto cancelled;
4400  }
4401  }
4402  if ( SortBotOut(BHEAD term1) < 0 ) {
4403  MLOCK(ErrorMessageLock);
4404  MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4405  MUNLOCK(ErrorMessageLock);
4406  error = -1;
4407  goto ReturnError;
4408  }
4409 cancelled:; /* Now we need two new terms */
4410  im = *term1;
4411  next = term1 + im;
4412  if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
4413  next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
4414  if ( blin1 == 1 ) {
4415  UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4416  }
4417  else {
4418  UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4419  }
4420  if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4421 /*
4422  Move the remainder down into block 0
4423 */
4424  to = Bin1->T.SB.MasterStart[1];
4425  from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
4426  while ( from > next ) *--to = *--from;
4427  next = to;
4428  blin1 = 1;
4429  }
4430  else {
4431  blin1++;
4432  }
4433  LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4434  Bin1->T.SB.MasterBlock = blin1;
4435  }
4436  term1 = next;
4437  goto next2;
4438 /*
4439  #] Equal :
4440 */
4441  }
4442  }
4443 /*
4444  Copy the tail
4445 */
4446  if ( *term1 ) {
4447 /*
4448  #[ Tail in one :
4449 */
4450  while ( *term1 ) {
4451  if ( SortBotOut(BHEAD term1) < 0 ) {
4452  MLOCK(ErrorMessageLock);
4453  MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4454  MUNLOCK(ErrorMessageLock);
4455  error = -1;
4456  goto ReturnError;
4457  }
4458  im = *term1;
4459  next = term1 + im;
4460  if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
4461  next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
4462  if ( blin1 == 1 ) {
4463  UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4464  }
4465  else {
4466  UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4467  }
4468  if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4469 /*
4470  Move the remainder down into block 0
4471 */
4472  to = Bin1->T.SB.MasterStart[1];
4473  from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
4474  while ( from > next ) *--to = *--from;
4475  next = to;
4476  blin1 = 1;
4477  }
4478  else {
4479  blin1++;
4480  }
4481  LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4482  Bin1->T.SB.MasterBlock = blin1;
4483  }
4484  term1 = next;
4485  }
4486 /*
4487  #] Tail in one :
4488 */
4489  }
4490  else if ( *term2 ) {
4491 /*
4492  #[ Tail in two :
4493 */
4494  while ( *term2 ) {
4495  if ( SortBotOut(BHEAD term2) < 0 ) {
4496  MLOCK(ErrorMessageLock);
4497  MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
4498  MUNLOCK(ErrorMessageLock);
4499  error = -1;
4500  goto ReturnError;
4501  }
4502  im = *term2;
4503  next = term2 + im;
4504  if ( next >= Bin2->T.SB.MasterStop[blin2] || ( *next
4505  && next+*next+COMPINC > Bin2->T.SB.MasterStop[blin2] ) ) {
4506  if ( blin2 == 1 ) {
4507  UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4508  }
4509  else {
4510  UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4511  }
4512  if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4513 /*
4514  Move the remainder down into block 0
4515 */
4516  to = Bin2->T.SB.MasterStart[1];
4517  from = Bin2->T.SB.MasterStop[Bin2->T.SB.MasterNumBlocks];
4518  while ( from > next ) *--to = *--from;
4519  next = to;
4520  blin2 = 1;
4521  }
4522  else {
4523  blin2++;
4524  }
4525  LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4526  Bin2->T.SB.MasterBlock = blin2;
4527  }
4528  term2 = next;
4529  }
4530 /*
4531  #] Tail in two :
4532 */
4533  }
4534  SortBotOut(BHEAD 0);
4535 ReturnError:;
4536 /*
4537  Release all locks
4538 */
4539  UNLOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4540  if ( blin1 > 1 ) {
4541  UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4542  }
4543  else {
4544  UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4545  }
4546  UNLOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4547  if ( blin2 > 1 ) {
4548  UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4549  }
4550  else {
4551  UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4552  }
4553  if ( AT.identity > 0 ) {
4554  UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
4555  }
4556 /*
4557  And that was all folks
4558 */
4559  return(error);
4560 }
4561 
4562 #endif
4563 
4564 /*
4565  #] SortBotMerge :
4566  #[ IniSortBlocks :
4567 */
4568 
4569 static int SortBlocksInitialized = 0;
4570 
4577 int IniSortBlocks(int numworkers)
4578 {
4579  ALLPRIVATES *B;
4580  SORTING *S;
4581  LONG totalsize, workersize, blocksize, numberofterms;
4582  int maxter, id, j;
4583  int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
4584  WORD *w;
4585 
4586  if ( SortBlocksInitialized ) return(0);
4587  SortBlocksInitialized = 1;
4588  if ( numworkers == 0 ) return(0);
4589 
4590 #ifdef WITHSORTBOTS
4591  if ( numworkers > 2 ) {
4592  numparts = 2*numworkers - 2;
4593  numberofblocks = numberofblocks/2;
4594  }
4595  else {
4596  numparts = numworkers;
4597  }
4598 #else
4599  numparts = numworkers;
4600 #endif
4601  S = AM.S0;
4602  totalsize = S->LargeSize + S->SmallEsize;
4603  workersize = totalsize / numparts;
4604  maxter = AM.MaxTer/sizeof(WORD);
4605  blocksize = ( workersize - maxter )/numberofblocks;
4606  numberofterms = blocksize / maxter;
4607  if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
4608 /*
4609  This should have been taken care of in RecalcSetups.
4610 */
4611  MesPrint("We have a problem with the size of the blocks in IniSortBlocks");
4612  Terminate(-1);
4613  }
4614 /*
4615  Layout: For each worker
4616  block 0: size is maxter WORDS
4617  numberofblocks blocks of size blocksize WORDS
4618 */
4619  w = S->lBuffer;
4620  if ( w == 0 ) w = S->sBuffer;
4621  for ( id = 1; id <= numparts; id++ ) {
4622  B = AB[id];
4623  AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
4624  sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
4625  AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
4626  AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
4627  AT.SB.MasterStop = AT.SB.MasterFill + (numberofblocks+1);
4628  AT.SB.MasterNumBlocks = numberofblocks;
4629  AT.SB.MasterBlock = 0;
4630  AT.SB.FillBlock = 0;
4631  AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
4632  w += maxter;
4633  AT.SB.MasterStop[0] = w;
4634  AT.SB.MasterBlockLock[0] = dummylock;
4635  for ( j = 1; j <= numberofblocks; j++ ) {
4636  AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
4637  w += blocksize;
4638  AT.SB.MasterStop[j] = w;
4639  AT.SB.MasterBlockLock[j] = dummylock;
4640  }
4641  }
4642  if ( w > S->sTop2 ) {
4643  MesPrint("Counting problem in IniSortBlocks");
4644  Terminate(-1);
4645  }
4646  return(0);
4647 }
4648 
4649 /*
4650  #] IniSortBlocks :
4651  #[ DefineSortBotTree :
4652 */
4653 
4654 #ifdef WITHSORTBOTS
4655 
4661 void DefineSortBotTree()
4662 {
4663  ALLPRIVATES *B;
4664  int n, i, from;
4665  if ( numberofworkers <= 2 ) return;
4666  n = numberofworkers*2-2;
4667  for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
4668  B = AB[i];
4669  AT.SortBotIn1 = from++;
4670  AT.SortBotIn2 = from++;
4671  }
4672  B = AB[0];
4673  AT.SortBotIn1 = from++;
4674  AT.SortBotIn2 = from++;
4675 }
4676 
4677 #endif
4678 
4679 /*
4680  #] DefineSortBotTree :
4681  #[ GetTerm2 :
4682 
4683  Routine does a GetTerm but only when a bracket index is involved and
4684  only from brackets that have been judged not suitable for treatment
4685  as complete brackets by a single worker. Whether or not a bracket should
4686  be treated by a single worker is decided by TreatIndexEntry
4687 */
4688 
4689 WORD GetTerm2(PHEAD WORD *term)
4690 {
4691  WORD *ttco, *tt, retval;
4692  LONG n,i;
4693  FILEHANDLE *fi;
4694  EXPRESSIONS e = AN.expr;
4695  BRACKETINFO *b = e->bracketinfo;
4696  BRACKETINDEX *bi = b->indexbuffer;
4697  POSITION where, eonfile = AS.OldOnFile[e-Expressions], bstart, bnext;
4698 /*
4699  1: Get the current position.
4700 */
4701  switch ( e->status ) {
4702  case UNHIDELEXPRESSION:
4703  case UNHIDEGEXPRESSION:
4704  case DROPHLEXPRESSION:
4705  case DROPHGEXPRESSION:
4706  case HIDDENLEXPRESSION:
4707  case HIDDENGEXPRESSION:
4708  fi = AR.hidefile;
4709  break;
4710  default:
4711  fi = AR.infile;
4712  break;
4713  }
4714  if ( AR.KeptInHold ) {
4715  retval = GetTerm(BHEAD term);
4716  return(retval);
4717  }
4718  SeekScratch(fi,&where);
4719  if ( AN.lastinindex < 0 ) {
4720 /*
4721  We have to test whether we have to do the first bracket
4722 */
4723  if ( ( n = TreatIndexEntry(BHEAD 0) ) <= 0 ) {
4724  AN.lastinindex = n;
4725  where = bi[n].start;
4726  ADD2POS(where,eonfile);
4727  SetScratch(fi,&where);
4728 /*
4729  Put the bracket in the Compress buffer.
4730 */
4731  ttco = AR.CompressBuffer;
4732  tt = b->bracketbuffer + bi[0].bracket;
4733  i = *tt;
4734  NCOPY(ttco,tt,i)
4735  AR.CompressPointer = ttco;
4736  retval = GetTerm(BHEAD term);
4737  return(retval);
4738  }
4739  else AN.lastinindex = n-1;
4740  }
4741 /*
4742  2: Find the corresponding index number
4743  a: test whether it is in the current bracket
4744 */
4745  n = AN.lastinindex;
4746  bstart = bi[n].start;
4747  ADD2POS(bstart,eonfile);
4748  bnext = bi[n].next;
4749  ADD2POS(bnext,eonfile);
4750  if ( ISLESSPOS(bstart,where) && ISLESSPOS(where,bnext) ) {
4751  retval = GetTerm(BHEAD term);
4752  return(retval);
4753  }
4754  for ( n++ ; n < b->indexfill; n++ ) {
4755  i = TreatIndexEntry(BHEAD n);
4756  if ( i <= 0 ) {
4757 /*
4758  Put the bracket in the Compress buffer.
4759 */
4760  ttco = AR.CompressBuffer;
4761  tt = b->bracketbuffer + bi[n].bracket;
4762  i = *tt;
4763  NCOPY(ttco,tt,i)
4764  AR.CompressPointer = ttco;
4765  AN.lastinindex = n;
4766  where = bi[n].start;
4767  ADD2POS(where,eonfile);
4768  SetScratch(fi,&(where));
4769  retval = GetTerm(BHEAD term);
4770  return(retval);
4771  }
4772  else n += i - 1;
4773  }
4774  return(0);
4775 }
4776 
4777 /*
4778  #] GetTerm2 :
4779  #[ TreatIndexEntry :
4780 */
4789 int TreatIndexEntry(PHEAD LONG n)
4790 {
4791  BRACKETINFO *b = AN.expr->bracketinfo;
4792  LONG numbra = b->indexfill - 1, i;
4793  LONG totterms;
4794  BRACKETINDEX *bi;
4795  POSITION pos1, average;
4796 /*
4797  1: number of the bracket should be such that there is one bucket
4798  for each worker remaining.
4799 */
4800  if ( ( numbra - n ) <= numberofworkers ) return(0);
4801 /*
4802  2: size of the bracket contents should be less than what remains in
4803  the expression divided by the number of workers.
4804 */
4805  bi = b->indexbuffer;
4806  DIFPOS(pos1,bi[numbra].next,bi[n].next); /* Size of what remains */
4807  BASEPOSITION(average) = DIVPOS(pos1,(3*numberofworkers));
4808  DIFPOS(pos1,bi[n].next,bi[n].start); /* Size of the current bracket */
4809  if ( ISLESSPOS(average,pos1) ) return(0);
4810 /*
4811  It passes.
4812  Now check whether we can do more brackets
4813 */
4814  totterms = bi->termsinbracket;
4815  if ( totterms > 2*AC.ThreadBucketSize ) return(1);
4816  for ( i = 1; i < numbra-n; i++ ) {
4817  DIFPOS(pos1,bi[n+i].next,bi[n].start); /* Size of the combined brackets */
4818  if ( ISLESSPOS(average,pos1) ) return(i);
4819  totterms += bi->termsinbracket;
4820  if ( totterms > 2*AC.ThreadBucketSize ) return(i+1);
4821  }
4822 /*
4823  We have a problem at the end of the system. Just do one.
4824 */
4825  return(1);
4826 }
4827 
4828 /*
4829  #] TreatIndexEntry :
4830  #[ SetHideFiles :
4831 */
4832 
4833 void SetHideFiles() {
4834  int i;
4835  ALLPRIVATES *B, *B0 = AB[0];
4836  for ( i = 1; i <= numberofworkers; i++ ) {
4837  B = AB[i];
4838  AR.hidefile->handle = AR0.hidefile->handle;
4839  if ( AR.hidefile->handle < 0 ) {
4840  AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
4841  AR.hidefile->POstop = AR0.hidefile->POstop;
4842  AR.hidefile->POfill = AR0.hidefile->POfill;
4843  AR.hidefile->POfull = AR0.hidefile->POfull;
4844  AR.hidefile->POsize = AR0.hidefile->POsize;
4845  AR.hidefile->POposition = AR0.hidefile->POposition;
4846  AR.hidefile->filesize = AR0.hidefile->filesize;
4847  }
4848  else {
4849  AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
4850  AR.hidefile->POstop = AR.hidefile->wPOstop;
4851  AR.hidefile->POfill = AR.hidefile->wPOfill;
4852  AR.hidefile->POfull = AR.hidefile->wPOfull;
4853  AR.hidefile->POsize = AR.hidefile->wPOsize;
4854  PUTZERO(AR.hidefile->POposition);
4855  }
4856  }
4857 }
4858 
4859 /*
4860  #] SetHideFiles :
4861  #[ IniFbufs :
4862 */
4863 
4864 void IniFbufs(VOID)
4865 {
4866  int i;
4867  for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
4868  IniFbuffer(AB[i]->T.fbufnum);
4869  }
4870 }
4871 
4872 /*
4873  #] IniFbufs :
4874  #[ SetMods :
4875 */
4876 
4877 void SetMods()
4878 {
4879  ALLPRIVATES *B;
4880  int i, n, j;
4881  for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
4882  B = AB[j];
4883  AN.ncmod = AC.ncmod;
4884  if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
4885  n = ABS(AN.ncmod);
4886  AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
4887  for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
4888  }
4889 }
4890 
4891 /*
4892  #] SetMods :
4893  #[ UnSetMods :
4894 */
4895 
4896 void UnSetMods()
4897 {
4898  ALLPRIVATES *B;
4899  int j;
4900  for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
4901  B = AB[j];
4902  if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
4903  AN.cmod = 0;
4904  }
4905 }
4906 
4907 /*
4908  #] UnSetMods :
4909  #[ find_Horner_MCTS_expand_tree_threaded :
4910 */
4911 
4912 void find_Horner_MCTS_expand_tree_threaded() {
4913  int id;
4914  while (( id = GetAvailableThread() ) < 0)
4915  MasterWait();
4916  WakeupThread(id,MCTSEXPANDTREE);
4917 }
4918 
4919 /*
4920  #] find_Horner_MCTS_expand_tree_threaded :
4921  #[ optimize_expression_given_Horner_threaded :
4922 */
4923 
4924 extern void optimize_expression_given_Horner_threaded() {
4925  int id;
4926  while (( id = GetAvailableThread() ) < 0)
4927  MasterWait();
4928  WakeupThread(id,OPTIMIZEEXPRESSION);
4929 }
4930 
4931 /*
4932  #] optimize_expression_given_Horner_threaded :
4933 */
4934 
4935 #endif
int NormalModulus(UWORD *, WORD *)
Definition: reken.c:1393
VOID AddArgs(PHEAD WORD *, WORD *, WORD *)
Definition: sort.c:2224
WORD * bracketbuffer
Definition: structs.h:318
Definition: structs.h:620
VOID WriteStats(POSITION *, WORD)
Definition: sort.c:91
#define PHEAD
Definition: ftypes.h:56
int inicbufs(VOID)
Definition: comtool.c:47
WORD ** lhs
Definition: structs.h:925
Definition: structs.h:921
WORD * Pointer
Definition: structs.h:924
WORD StoreTerm(PHEAD WORD *)
Definition: sort.c:4246
WORD ** rhs
Definition: structs.h:926
WORD Compare1(PHEAD WORD *, WORD *, WORD)
Definition: sort.c:2509
Definition: structs.h:1069
struct NeStInG * NESTING
struct StOrEcAcHe * STORECACHE
VOID LowerSortLevel()
Definition: sort.c:4610
BRACKETINDEX * indexbuffer
Definition: structs.h:317
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition: sort.c:1387
WORD * Buffer
Definition: structs.h:922
WORD NewSort(PHEAD0)
Definition: sort.c:589
WORD Generator(PHEAD WORD *, WORD)
Definition: proces.c:3034
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition: sort.c:1724
LONG TimeCPU(WORD)
Definition: tools.c:3418
int handle
Definition: structs.h:648
LONG EndSort(PHEAD WORD *, int)
Definition: sort.c:675
int IniFbuffer(WORD bufnum)
Definition: comtool.c:614