FORM v5.0.2-2-gfb12f2e
threads.c
Go to the documentation of this file.
1
22/* #[ License : */
23/*
24 * Copyright (C) 1984-2026 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 constitute
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 (SortBotMasterMerge)
59 is much simpler for the sortbots.
60*/
61
62#include "form3.h"
63#include <math.h>
64
65#ifdef WITH_ALARM
66// This is only required if we are blocking SIG_ALRM in the worker threads.
67#include <signal.h>
68#endif
69
70#ifdef WITHFLOAT
71#include <gmp.h>
72
73int PackFloat(WORD *,mpf_t);
74int UnpackFloat(mpf_t, WORD *);
75void RatToFloat(mpf_t result, UWORD *formrat, int ratsize);
76#endif
77
78static int numberofthreads;
79static int numberofworkers;
80static int identityofthreads = 0;
81static int *listofavailables;
82static int topofavailables = 0;
83static pthread_key_t identitykey;
84static INILOCK(numberofthreadslock)
85static INILOCK(availabilitylock)
86static pthread_t *threadpointers = 0;
87static pthread_mutex_t *wakeuplocks;
88static pthread_mutex_t *wakeupmasterthreadlocks;
89static pthread_cond_t *wakeupconditions;
90static pthread_condattr_t *wakeupconditionattributes;
91static int *wakeup;
92static int *wakeupmasterthread;
93static INILOCK(wakeupmasterlock)
94static pthread_cond_t wakeupmasterconditions = PTHREAD_COND_INITIALIZER;
95static pthread_cond_t *wakeupmasterthreadconditions;
96static int wakeupmaster = 0;
97static int identityretval;
98/* static INILOCK(clearclocklock) */
99static LONG *timerinfo;
100static LONG *sumtimerinfo;
101static int numberclaimed;
102
103static THREADBUCKET **threadbuckets, **freebuckets;
104static int numthreadbuckets;
105static int numberoffullbuckets;
106
107/* static int numberbusy = 0; */
108
109INILOCK(dummylock)
110INIRWLOCK(dummyrwlock)
111static pthread_cond_t dummywakeupcondition = PTHREAD_COND_INITIALIZER;
112
113static POSITION SortBotPosition;
114static INILOCK(wakeupsortbotlock)
115static pthread_cond_t wakeupsortbotconditions = PTHREAD_COND_INITIALIZER;
116static int topsortbotavailables = 0;
117static LONG numberofterms;
118
119/*
120 #] Variables :
121 #[ Identity :
122 #[ StartIdentity :
123*/
129void StartIdentity(void)
130{
131 pthread_key_create(&identitykey,FinishIdentity);
132}
133
134/*
135 #] StartIdentity :
136 #[ FinishIdentity :
137*/
142void FinishIdentity(void *keyp)
143{
144 DUMMYUSE(keyp);
145/* free(keyp); */
146}
147
148/*
149 #] FinishIdentity :
150 #[ SetIdentity :
151*/
156int SetIdentity(int *identityretval)
157{
158/*
159#ifdef _MSC_VER
160 printf("addr %d\n",&numberofthreadslock);
161 printf("size %d\n",sizeof(numberofthreadslock));
162#endif
163*/
164 LOCK(numberofthreadslock);
165 *identityretval = identityofthreads++;
166 UNLOCK(numberofthreadslock);
167 pthread_setspecific(identitykey,(void *)identityretval);
168 return(*identityretval);
169}
170
171/*
172 #] SetIdentity :
173 #[ WhoAmI :
174*/
175
186int WhoAmI(void)
187{
188 int *identity;
189/*
190 First a fast exit for when there is at most one thread
191*/
192 if ( identityofthreads <= 1 ) return(0);
193/*
194 Now the reading of the key.
195 According to the book the statement should read:
196
197 pthread_getspecific(identitykey,(void **)(&identity));
198
199 but according to the information in pthread.h it is:
200*/
201 identity = (int *)pthread_getspecific(identitykey);
202 return(*identity);
203}
204
205/*
206 #] WhoAmI :
207 #[ BeginIdentities :
208*/
214void BeginIdentities(void)
215{
216 StartIdentity();
217 SetIdentity(&identityretval);
218}
219
220/*
221 #] BeginIdentities :
222 #] Identity :
223 #[ StartHandleLock :
224*/
231void StartHandleLock(void)
232{
233 AM.handlelock = dummyrwlock;
234}
235
236/*
237 #] StartHandleLock :
238 #[ GetNumberOfSortBots :
239*/
243int GetNumberOfSortBots(int numberofworkers)
244{
245 if (numberofworkers <= 1)
246 return 0;
247
248 return numberofworkers - 1;
249}
250/*
251 #] GetNumberOfSortBots :
252 #[ StartAllThreads :
253*/
271int StartAllThreads(int number)
272{
273 int identity, j, dummy, mul;
274 ALLPRIVATES *B;
275 pthread_t thethread;
276 identity = WhoAmI();
277
278
279 timerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"timerinfo");
280 sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"sumtimerinfo");
281 for ( j = 0; j < number*2; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
282 mul = 2;
283
284 listofavailables = (int *)Malloc1(sizeof(int)*(number+1),"listofavailables");
285 threadpointers = (pthread_t *)Malloc1(sizeof(pthread_t)*number*mul,"threadpointers");
286 AB = (ALLPRIVATES **)Malloc1(sizeof(ALLPRIVATES *)*number*mul,"Private structs");
287
288 wakeup = (int *)Malloc1(sizeof(int)*number*mul,"wakeup");
289 wakeuplocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeuplocks");
290 wakeupconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupconditions");
291 wakeupconditionattributes = (pthread_condattr_t *)
292 Malloc1(sizeof(pthread_condattr_t)*number*mul,"wakeupconditionattributes");
293
294 wakeupmasterthread = (int *)Malloc1(sizeof(int)*number*mul,"wakeupmasterthread");
295 wakeupmasterthreadlocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeupmasterthreadlocks");
296 wakeupmasterthreadconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupmasterthread");
297
298 numberofthreads = number;
299 numberofworkers = number - 1;
300 threadpointers[identity] = pthread_self();
301 topofavailables = 0;
302
303#ifdef WITH_ALARM
304 /* During thread creation, we block SIGALRM on the main thread. The created
305 threads will inherit this. This is required for #timeout to work properly
306 in TFORM: only the main thread should recieve SIGALRM. */
307 sigset_t sig_set;
308 sigemptyset(&sig_set);
309 sigaddset(&sig_set, SIGALRM);
310 pthread_sigmask(SIG_BLOCK, &sig_set, NULL);
311#endif
312
313 for ( j = 1; j < number; j++ ) {
314 if ( pthread_create(&thethread,NULL,RunThread,(void *)(&dummy)) )
315 goto failure;
316 }
317/*
318 Now we initialize the master at the same time that the workers are doing so.
319*/
320 B = InitializeOneThread(identity);
321 AR.infile = &(AR.Fscr[0]);
322 AR.outfile = &(AR.Fscr[1]);
323 AR.hidefile = &(AR.Fscr[2]);
324 AM.sbuflock = dummylock;
325 AS.inputslock = dummylock;
326 AS.outputslock = dummylock;
327 AS.MaxExprSizeLock = dummylock;
328 AP.PreVarLock = dummylock;
329 AC.halfmodlock = dummylock;
330 MakeThreadBuckets(number,0);
331/*
332 Now we wait for the workers to finish their startup.
333 We don't want to initialize the sortbots yet and run the risk that
334 some of them may end up with a lower number than one of the workers.
335*/
336 MasterWaitAll();
337
338 for ( j = 0; j < GetNumberOfSortBots(numberofworkers); j++ ) {
339 if ( pthread_create(&thethread,NULL,RunSortBot,(void *)(&dummy)) )
340 goto failure;
341 }
342 MasterWaitAllSortBots();
343 DefineSortBotTree();
344 IniSortBlocks(number-1);
345 AS.MasterSort = 0;
346 AM.storefilelock = dummylock;
347
348#ifdef WITH_ALARM
349 /* Now we allow the main thread to recieve SIGALRM again. */
350 pthread_sigmask(SIG_UNBLOCK, &sig_set, NULL);
351#endif
352
353/*
354MesPrint("AB = %x %x %x %d",AB[0],AB[1],AB[2], identityofthreads);
355*/
356 return(0);
357/* INTERNAL_ERROR_EXCL_START */
358failure:
359 MesPrint("!>Cannot start %d threads",number);
360 Terminate(-1);
361 return(-1);
362/* INTERNAL_ERROR_EXCL_STOP */
363}
364
365/*
366 #] StartAllThreads :
367 #[ InitializeOneThread :
368*/
372UBYTE *scratchname[] = { (UBYTE *)"scratchsize",
373 (UBYTE *)"scratchsize",
374 (UBYTE *)"hidesize" };
401ALLPRIVATES *InitializeOneThread(int identity)
402{
403 WORD *t, *ScratchBuf;
404 int i, j, bsize, *bp;
405 LONG ScratchSize[3], IOsize;
406 ALLPRIVATES *B;
407 UBYTE *s;
408
409 wakeup[identity] = 0;
410 wakeuplocks[identity] = dummylock;
411 pthread_condattr_init(&(wakeupconditionattributes[identity]));
412 pthread_condattr_setpshared(&(wakeupconditionattributes[identity]),PTHREAD_PROCESS_PRIVATE);
413 wakeupconditions[identity] = dummywakeupcondition;
414 pthread_cond_init(&(wakeupconditions[identity]),&(wakeupconditionattributes[identity]));
415 wakeupmasterthread[identity] = 0;
416 wakeupmasterthreadlocks[identity] = dummylock;
417 wakeupmasterthreadconditions[identity] = dummywakeupcondition;
418
419 bsize = sizeof(ALLPRIVATES);
420 bsize = (bsize+sizeof(int)-1)/sizeof(int);
421 B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
422 for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
423
424 AB[identity] = B;
425/*
426 12-jun-2007 JV:
427 For the timing one has to know a few things:
428 The POSIX standard is that there is only a single process ID and that
429 getrusage returns the time of all the threads together.
430 Under Linux there are two methods though: The older LinuxThreads and NPTL.
431 LinuxThreads gives each thread its own process id. This makes that we
432 can time the threads with getrusage, and hence this was done. Under NPTL
433 this has been 'corrected' and suddenly getruage doesn't work anymore the
434 way it used to. Now we need
435 clock_gettime(CLOCK_THREAD_CPUTIME_ID,&timing)
436 which is declared in <time.h> and we need -lrt extra in the link statement.
437 (this is at least the case on blade02 at DESY-Zeuthen).
438 See also the code in tools.c at the routine Timer.
439 We may still have to include more stuff there.
440*/
441 if ( identity > 0 ) TimeCPU(0);
442
443
444 if ( identity > numberofworkers ) {
445/*
446 Some workspace is needed when we have a PolyFun and we have to add
447 two terms and the new result is going to be longer than the old result.
448*/
449 LONG length = AM.WorkSize*sizeof(WORD)/8+AM.MaxTer*2;
450 AT.WorkSpace = (WORD *)Malloc1(length,"WorkSpace");
451 AT.WorkTop = AT.WorkSpace + length/sizeof(WORD);
452 AT.WorkPointer = AT.WorkSpace;
453 AT.identity = identity;
454/*
455 The SB struct gets treated in IniSortBlocks.
456 The SortBotIn variables will be defined DefineSortBotTree.
457*/
458 if ( AN.SoScratC == 0 ) {
459 AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
460 }
461 AT.SS = (SORTING *)Malloc1(sizeof(SORTING),"dummy sort buffer");
462 AT.SS->PolyFlag = 0;
463
464 AT.comsym[0] = 8;
465 AT.comsym[1] = SYMBOL;
466 AT.comsym[2] = 4;
467 AT.comsym[3] = 0;
468 AT.comsym[4] = 1;
469 AT.comsym[5] = 1;
470 AT.comsym[6] = 1;
471 AT.comsym[7] = 3;
472 AT.comnum[0] = 4;
473 AT.comnum[1] = 1;
474 AT.comnum[2] = 1;
475 AT.comnum[3] = 3;
476 AT.comfun[0] = FUNHEAD+4;
477 AT.comfun[1] = FUNCTION;
478 AT.comfun[2] = FUNHEAD;
479 AT.comfun[3] = 0;
480#if FUNHEAD > 3
481 for ( i = 4; i <= FUNHEAD; i++ )
482 AT.comfun[i] = 0;
483#endif
484 AT.comfun[FUNHEAD+1] = 1;
485 AT.comfun[FUNHEAD+2] = 1;
486 AT.comfun[FUNHEAD+3] = 3;
487 AT.comind[0] = 7;
488 AT.comind[1] = INDEX;
489 AT.comind[2] = 3;
490 AT.comind[3] = 0;
491 AT.comind[4] = 1;
492 AT.comind[5] = 1;
493 AT.comind[6] = 3;
494
495 AT.inprimelist = -1;
496 AT.sizeprimelist = 0;
497 AT.primelist = 0;
498 AT.bracketinfo = 0;
499
500 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
501
502 AR.sLevel = 0;
503 AR.wranfia = 0;
504 AR.wranfcall = 0;
505 AR.wranfnpair1 = NPAIR1;
506 AR.wranfnpair2 = NPAIR2;
507 AN.NumFunSorts = 5;
508 AN.MaxFunSorts = 5;
509 AN.SplitScratch = 0;
510 AN.SplitScratchSize = AN.InScratch = 0;
511 AN.SplitScratch1 = 0;
512 AN.SplitScratchSize1 = AN.InScratch1 = 0;
513
514 AN.FunSorts = (SORTING **)Malloc1((AN.NumFunSorts+1)*sizeof(SORTING *),"FunSort pointers");
515 for ( i = 0; i <= AN.NumFunSorts; i++ ) AN.FunSorts[i] = 0;
516 AN.FunSorts[0] = AT.S0 = AT.SS;
517 AN.idfunctionflag = 0;
518 AN.tryterm = 0;
519
520 return(B);
521 }
522 if ( identity == 0 && AN.SoScratC == 0 ) {
523 AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
524 }
525 AR.CurDum = AM.IndDum;
526 for ( j = 0; j < 3; j++ ) {
527 if ( identity == 0 ) {
528 if ( j == 2 ) {
529 ScratchSize[j] = AM.HideSize;
530 }
531 else {
532 ScratchSize[j] = AM.ScratSize;
533 }
534 if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
535 }
536 else {
537/*
538 ScratchSize[j] = AM.ScratSize / (numberofthreads-1);
539 ScratchSize[j] = ScratchSize[j] / 20;
540 if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
541*/
542 if ( j == 1 ) ScratchSize[j] = AM.ThreadScratOutSize;
543 else ScratchSize[j] = AM.ThreadScratSize;
544 if ( ScratchSize[j] < 4*AM.MaxTer ) ScratchSize[j] = 4 * AM.MaxTer;
545 AR.Fscr[j].name = 0;
546 }
547 ScratchSize[j] = ( ScratchSize[j] + 255 ) / 256;
548 ScratchSize[j] = ScratchSize[j] * 256;
549 ScratchBuf = (WORD *)Malloc1(ScratchSize[j]*sizeof(WORD),(char *)(scratchname[j]));
550 AR.Fscr[j].POsize = ScratchSize[j] * sizeof(WORD);
551 AR.Fscr[j].POfull = AR.Fscr[j].POfill = AR.Fscr[j].PObuffer = ScratchBuf;
552 AR.Fscr[j].POstop = AR.Fscr[j].PObuffer + ScratchSize[j];
553 PUTZERO(AR.Fscr[j].POposition);
554 AR.Fscr[j].pthreadslock = dummylock;
555 AR.Fscr[j].wPOsize = AR.Fscr[j].POsize;
556 AR.Fscr[j].wPObuffer = AR.Fscr[j].PObuffer;
557 AR.Fscr[j].wPOfill = AR.Fscr[j].POfill;
558 AR.Fscr[j].wPOfull = AR.Fscr[j].POfull;
559 AR.Fscr[j].wPOstop = AR.Fscr[j].POstop;
560 }
561 AR.InInBuf = 0;
562 AR.InHiBuf = 0;
563 AR.Fscr[0].handle = -1;
564 AR.Fscr[1].handle = -1;
565 AR.Fscr[2].handle = -1;
566 AR.FoStage4[0].handle = -1;
567 AR.FoStage4[1].handle = -1;
568 IOsize = AM.S0->file.POsize;
569#ifdef WITHZLIB
570 AR.FoStage4[0].ziosize = IOsize;
571 AR.FoStage4[1].ziosize = IOsize;
572 AR.FoStage4[0].ziobuffer = 0;
573 AR.FoStage4[1].ziobuffer = 0;
574#endif
575 AR.FoStage4[0].POsize = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
576 AR.FoStage4[1].POsize = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
577
578 AR.hidefile = &(AR.Fscr[2]);
579 AR.StoreData.Handle = -1;
580 AR.SortType = AC.SortType;
581
582 AN.IndDum = AM.IndDum;
583
584 if ( identity > 0 ) {
585 s = (UBYTE *)(FG.fname); i = 0;
586 while ( *s ) { s++; i++; }
587 s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[0] file");
588 snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
589 s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '0';
590 AR.Fscr[0].name = (char *)s;
591 s = (UBYTE *)(FG.fname); i = 0;
592 while ( *s ) { s++; i++; }
593 s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[1] file");
594 snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
595 s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '1';
596 AR.Fscr[1].name = (char *)s;
597 }
598
599 AR.CompressBuffer = (WORD *)Malloc1((AM.CompressSize+10)*sizeof(WORD),"compresssize");
600 AR.ComprTop = AR.CompressBuffer + AM.CompressSize;
601 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
602/*
603 Here we make all allocations for the struct AT
604 (which is AB[identity].T or B->T with B = AB+identity).
605*/
606 AT.WorkSpace = (WORD *)Malloc1(AM.WorkSize*sizeof(WORD),"WorkSpace");
607 AT.WorkTop = AT.WorkSpace + AM.WorkSize;
608 AT.WorkPointer = AT.WorkSpace;
609
610 AT.Nest = (NESTING)Malloc1((LONG)sizeof(struct NeStInG)*AM.maxFlevels,"functionlevels");
611 AT.NestStop = AT.Nest + AM.maxFlevels;
612 AT.NestPoin = AT.Nest;
613
614 AT.WildMask = (WORD *)Malloc1((LONG)AM.MaxWildcards*sizeof(WORD),"maxwildcards");
615
616 LOCK(availabilitylock);
617 AT.ebufnum = inicbufs(); /* Buffer for extras during execution */
618 AT.fbufnum = inicbufs(); /* Buffer for caching in factorization */
619 AT.allbufnum = inicbufs(); /* Buffer for id,all */
620 AT.aebufnum = inicbufs(); /* Buffer for id,all */
621 UNLOCK(availabilitylock);
622
623 AT.RepCount = (int *)Malloc1((LONG)((AM.RepMax+3)*sizeof(int)),"repeat buffers");
624 AN.RepPoint = AT.RepCount;
625 AN.polysortflag = 0;
626 AN.subsubveto = 0;
627 AN.tryterm = 0;
628 AT.RepTop = AT.RepCount + AM.RepMax;
629
630 AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
631 ,"argument list names");
632 AT.WildcardBufferSize = AC.WildcardBufferSize;
633 AT.previousEfactor = 0;
634
635 AT.identity = identity;
636 AT.LoadBalancing = 0;
637/*
638 Still to do: the SS stuff.
639 the Fscr[3]
640 the FoStage4[2]
641*/
642 if ( AT.WorkSpace == 0 ||
643 AT.Nest == 0 ||
644 AT.WildMask == 0 ||
645 AT.RepCount == 0 ||
646 AT.WildArgTaken == 0 ) goto OnError;
647/*
648 And initializations
649*/
650 AT.comsym[0] = 8;
651 AT.comsym[1] = SYMBOL;
652 AT.comsym[2] = 4;
653 AT.comsym[3] = 0;
654 AT.comsym[4] = 1;
655 AT.comsym[5] = 1;
656 AT.comsym[6] = 1;
657 AT.comsym[7] = 3;
658 AT.comnum[0] = 4;
659 AT.comnum[1] = 1;
660 AT.comnum[2] = 1;
661 AT.comnum[3] = 3;
662 AT.comfun[0] = FUNHEAD+4;
663 AT.comfun[1] = FUNCTION;
664 AT.comfun[2] = FUNHEAD;
665 AT.comfun[3] = 0;
666#if FUNHEAD > 3
667 for ( i = 4; i <= FUNHEAD; i++ )
668 AT.comfun[i] = 0;
669#endif
670 AT.comfun[FUNHEAD+1] = 1;
671 AT.comfun[FUNHEAD+2] = 1;
672 AT.comfun[FUNHEAD+3] = 3;
673 AT.comind[0] = 7;
674 AT.comind[1] = INDEX;
675 AT.comind[2] = 3;
676 AT.comind[3] = 0;
677 AT.comind[4] = 1;
678 AT.comind[5] = 1;
679 AT.comind[6] = 3;
680 AT.locwildvalue[0] = SUBEXPRESSION;
681 AT.locwildvalue[1] = SUBEXPSIZE;
682 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
683 AT.mulpat[0] = TYPEMULT;
684 AT.mulpat[1] = SUBEXPSIZE+3;
685 AT.mulpat[2] = 0;
686 AT.mulpat[3] = SUBEXPRESSION;
687 AT.mulpat[4] = SUBEXPSIZE;
688 AT.mulpat[5] = 0;
689 AT.mulpat[6] = 1;
690 for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
691 AT.proexp[0] = SUBEXPSIZE+4;
692 AT.proexp[1] = EXPRESSION;
693 AT.proexp[2] = SUBEXPSIZE;
694 AT.proexp[3] = -1;
695 AT.proexp[4] = 1;
696 for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
697 AT.proexp[SUBEXPSIZE+1] = 1;
698 AT.proexp[SUBEXPSIZE+2] = 1;
699 AT.proexp[SUBEXPSIZE+3] = 3;
700 AT.proexp[SUBEXPSIZE+4] = 0;
701 AT.dummysubexp[0] = SUBEXPRESSION;
702 AT.dummysubexp[1] = SUBEXPSIZE+4;
703 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
704 AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
705 AT.dummysubexp[SUBEXPSIZE+1] = 4;
706 AT.dummysubexp[SUBEXPSIZE+2] = 0;
707 AT.dummysubexp[SUBEXPSIZE+3] = 0;
708
709 AT.MinVecArg[0] = 7+ARGHEAD;
710 AT.MinVecArg[ARGHEAD] = 7;
711 AT.MinVecArg[1+ARGHEAD] = INDEX;
712 AT.MinVecArg[2+ARGHEAD] = 3;
713 AT.MinVecArg[3+ARGHEAD] = 0;
714 AT.MinVecArg[4+ARGHEAD] = 1;
715 AT.MinVecArg[5+ARGHEAD] = 1;
716 AT.MinVecArg[6+ARGHEAD] = -3;
717 t = AT.FunArg;
718 *t++ = 4+ARGHEAD+FUNHEAD;
719 for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
720 *t++ = 4+FUNHEAD;
721 *t++ = 0;
722 *t++ = FUNHEAD;
723 for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
724 *t++ = 1; *t++ = 1; *t++ = 3;
725
726 AT.inprimelist = -1;
727 AT.sizeprimelist = 0;
728 AT.primelist = 0;
729 AT.nfac = AT.nBer = 0;
730 AT.factorials = 0;
731 AT.bernoullis = 0;
732 AR.wranfia = 0;
733 AR.wranfcall = 0;
734 AR.wranfnpair1 = NPAIR1;
735 AR.wranfnpair2 = NPAIR2;
736 AR.wranfseed = 0;
737
738 AT.NormData = Malloc1(sizeof(*(AT.NormData)), "NormData thread pointers");
739 AT.NormDataSize = 1;
740 AT.NormData[0] = AllocNormData();
741 AT.NormDepth = 0;
742
743 AN.SplitScratch = 0;
744 AN.SplitScratchSize = AN.InScratch = 0;
745 AN.SplitScratch1 = 0;
746 AN.SplitScratchSize1 = AN.InScratch1 = 0;
747/*
748 Now the sort buffers. They depend on which thread. The master
749 inherits the sortbuffer from AM.S0
750*/
751 if ( identity == 0 ) {
752 AT.S0 = AM.S0;
753 }
754 else {
755/*
756 For the moment we don't have special settings.
757 They may become costly in virtual memory.
758*/
759 AT.S0 = AllocSort(AM.S0->LargeSize*sizeof(WORD)/numberofworkers
760 ,AM.S0->SmallSize*sizeof(WORD)/numberofworkers
761 ,AM.S0->SmallEsize*sizeof(WORD)/numberofworkers
762 ,AM.S0->TermsInSmall
763 ,AM.S0->MaxPatches
764/* ,AM.S0->MaxPatches/numberofworkers */
765 ,AM.S0->MaxFpatches/numberofworkers
766 ,AM.S0->file.POsize
767 ,0);
768 }
769 AR.CompressPointer = AR.CompressBuffer;
770/*
771 Install the store caches (15-aug-2006 JV)
772*/
773 AT.StoreCache = AT.StoreCacheAlloc = 0;
774 if ( AM.NumStoreCaches > 0 ) {
775 STORECACHE sa, sb;
776 LONG size;
777 size = sizeof(struct StOrEcAcHe)+AM.SizeStoreCache;
778 size = ((size-1)/sizeof(size_t)+1)*sizeof(size_t);
779 AT.StoreCacheAlloc = (STORECACHE)Malloc1(size*AM.NumStoreCaches,"StoreCaches");
780 sa = AT.StoreCache = AT.StoreCacheAlloc;
781 for ( i = 0; i < AM.NumStoreCaches; i++ ) {
782 sb = (STORECACHE)(void *)((UBYTE *)sa+size);
783 if ( i == AM.NumStoreCaches-1 ) {
784 sa->next = 0;
785 }
786 else {
787 sa->next = sb;
788 }
789 SETBASEPOSITION(sa->position,-1);
790 SETBASEPOSITION(sa->toppos,-1);
791 sa = sb;
792 }
793 }
794
795 ReserveTempFiles(2);
796 return(B);
797/* INTERNAL_ERROR_EXCL_START */
798OnError:;
799 MLOCK(ErrorMessageLock);
800 MesPrint("!>Error initializing thread %d",identity);
801 MUNLOCK(ErrorMessageLock);
802 Terminate(-1);
803 return(B);
804/* INTERNAL_ERROR_EXCL_STOP */
805}
806
807/*
808 #] InitializeOneThread :
809 #[ FinalizeOneThread :
810*/
821void FinalizeOneThread(int identity)
822{
823 timerinfo[identity] = TimeCPU(1);
824}
825
826/*
827 #] FinalizeOneThread :
828 #[ ClearAllThreads :
829*/
836void ClearAllThreads(void)
837{
838 int i;
839 MasterWaitAll();
840 for ( i = 1; i <= numberofworkers; i++ ) {
841 WakeupThread(i,CLEARCLOCK);
842 }
843 for ( i = numberofworkers+1; i <= numberofworkers+GetNumberOfSortBots(numberofworkers); i++ ) {
844 WakeupThread(i,CLEARCLOCK);
845 }
846}
847
848/*
849 #] ClearAllThreads :
850 #[ TerminateAllThreads :
851*/
858void TerminateAllThreads(void)
859{
860 int i;
861 for ( i = 1; i <= numberofworkers; i++ ) {
862 GetThread(i);
863 WakeupThread(i,TERMINATETHREAD);
864 }
865 for ( i = numberofworkers+1; i <= numberofworkers+GetNumberOfSortBots(numberofworkers); i++ ) {
866 WakeupThread(i,TERMINATETHREAD);
867 }
868 for ( i = 1; i <= numberofworkers; i++ ) {
869 pthread_join(threadpointers[i],NULL);
870 }
871 for ( i = numberofworkers+1; i <= numberofworkers+GetNumberOfSortBots(numberofworkers); i++ ) {
872 pthread_join(threadpointers[i],NULL);
873 }
874}
875
876/*
877 #] TerminateAllThreads :
878 #[ MakeThreadBuckets :
879*/
905int MakeThreadBuckets(int number, int par)
906{
907 int i;
908 LONG sizethreadbuckets;
909 THREADBUCKET *thr;
910
911 // Here we divide by 4, which has been the behaviour with the default
912 // AC.ThreadBucketSize for a long time.
913 // MAXTER is the default value of AM.MaxTer, in units of sizeof(WORD).
914 sizethreadbuckets = (AC.ThreadBucketSize*MAXTER)/4;
915 // Now we scale up the buffer logarithmically with the user AM.MaxTer.
916 // If we scale linearly, we end up with really enormous buffers here
917 // when AM.MaxTer is of the order of millions of WORDs.
918 float scale = 1.0;
919 if ( AM.MaxTer/sizeof(WORD) > MAXTER ) {
920 scale += log(((float)AM.MaxTer/sizeof(WORD))/MAXTER);
921 }
922 sizethreadbuckets = (LONG)((float)sizethreadbuckets*scale);
923 // Nonetheless, we must fit at least BUCKETMINTERMS terms in each bucket!
924 // So the buffer will eventually scale linearly with MaxTer anyway, but
925 // much less aggressively than the old code.
926 sizethreadbuckets = MaX((ULONG)sizethreadbuckets, BUCKETMINTERMS*AM.MaxTer/sizeof(WORD));
927
928 if ( par == 0 ) {
929 numthreadbuckets = 2*(number-1);
930 threadbuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
931 freebuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"freebuckets");
932 }
933 if ( par > 0 ) {
934 if ( sizethreadbuckets <= threadbuckets[0]->threadbuffersize ) return(0);
935 for ( i = 0; i < numthreadbuckets; i++ ) {
936 thr = threadbuckets[i];
937 M_free(thr->deferbuffer,"deferbuffer");
938 M_free(thr->threadbuffer,"threadbuffer");
939 M_free(thr->compressbuffer,"compressbuffer");
940 }
941 }
942 else {
943 for ( i = 0; i < numthreadbuckets; i++ ) {
944 threadbuckets[i] = (THREADBUCKET *)Malloc1(sizeof(THREADBUCKET),"threadbuckets");
945 threadbuckets[i]->lock = dummylock;
946 }
947 }
948 for ( i = 0; i < numthreadbuckets; i++ ) {
949 thr = threadbuckets[i];
950 thr->threadbuffersize = sizethreadbuckets;
951 // This buffer does not need to be so large, start it at MaxTer.
952 // We'll double it if necessary.
953 thr->compressbuffersize = AM.MaxTer/sizeof(WORD);
954 thr->free = BUCKETFREE;
955 thr->deferbuffer = (POSITION *)Malloc1((AC.ThreadBucketSize+1)*sizeof(POSITION),"deferbuffer");
956 thr->threadbuffer = (WORD *)Malloc1(sizethreadbuckets*sizeof(WORD),"threadbuffer");
957 thr->compressbuffer = (WORD *)Malloc1(thr->compressbuffersize*sizeof(WORD),"compressbuffer");
958 thr->busy = BUCKETPREPARINGTERM;
959 thr->usenum = thr->totnum = 0;
960 thr->type = BUCKETDOINGTERMS;
961 }
962 return(0);
963}
964
965/*
966 #] MakeThreadBuckets :
967 #[ GetTimerInfo :
968*/
969
975/* UNFINISHED_FEATURE_EXCL_START */
976int GetTimerInfo(LONG** ti,LONG** sti)
977{
978 *ti = timerinfo;
979 *sti = sumtimerinfo;
980 return (numberofworkers + GetNumberOfSortBots(numberofworkers) + 1);
981}
982/* UNFINISHED_FEATURE_EXCL_STOP */
983/*
984 #] GetTimerInfo :
985 #[ WriteTimerInfo :
986*/
987
992/* UNFINISHED_FEATURE_EXCL_START */
993void WriteTimerInfo(LONG* ti,LONG* sti)
994{
995 int i;
996 int max = (numberofworkers + GetNumberOfSortBots(numberofworkers) + 1);
997 for ( i=0; i<max; ++i ) {
998 timerinfo[i] = ti[i];
999 sumtimerinfo[i] = sti[i];
1000 }
1001}
1002/* UNFINISHED_FEATURE_EXCL_STOP */
1003/*
1004 #] WriteTimerInfo :
1005 #[ GetWorkerTimes :
1006*/
1012LONG GetWorkerTimes(void)
1013{
1014 LONG retval = 0;
1015 int i;
1016 for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
1017 for ( i = numberofworkers+1; i <= numberofworkers+GetNumberOfSortBots(numberofworkers); i++ )
1018 retval += timerinfo[i] + sumtimerinfo[i];
1019 return(retval);
1020}
1021
1022/*
1023 #] GetWorkerTimes :
1024 #[ UpdateOneThread :
1025*/
1032int UpdateOneThread(int identity)
1033{
1034 ALLPRIVATES *B = AB[identity], *B0 = AB[0];
1035 AR.GetFile = AR0.GetFile;
1036 AR.KeptInHold = AR0.KeptInHold;
1037 AR.CurExpr = AR0.CurExpr;
1038 AR.SortType = AC.SortType;
1039 if ( AT.WildcardBufferSize < AC.WildcardBufferSize ) {
1040 M_free(AT.WildArgTaken,"argument list names");
1041 AT.WildcardBufferSize = AC.WildcardBufferSize;
1042 AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
1043 ,"argument list names");
1044 if ( AT.WildArgTaken == 0 ) return(-1);
1045 }
1046 return(0);
1047}
1048
1049/*
1050 #] UpdateOneThread :
1051 #[ LoadOneThread :
1052*/
1066int LoadOneThread(int from, int identity, THREADBUCKET *thr, int par)
1067{
1068 WORD *t1, *t2;
1069 ALLPRIVATES *B = AB[identity], *B0 = AB[from];
1070
1071 AR.DefPosition = AR0.DefPosition;
1072 AR.NoCompress = AR0.NoCompress;
1073 AR.gzipCompress = AR0.gzipCompress;
1074 AR.BracketOn = AR0.BracketOn;
1075 AR.CurDum = AR0.CurDum;
1076 AR.DeferFlag = AR0.DeferFlag;
1077 AR.TePos = 0;
1078 AR.sLevel = AR0.sLevel;
1079 AR.Stage4Name = AR0.Stage4Name;
1080 AR.GetOneFile = AR0.GetOneFile;
1081 AR.PolyFun = AR0.PolyFun;
1082 AR.PolyFunInv = AR0.PolyFunInv;
1083 AR.PolyFunType = AR0.PolyFunType;
1084 AR.PolyFunExp = AR0.PolyFunExp;
1085 AR.PolyFunVar = AR0.PolyFunVar;
1086 AR.PolyFunPow = AR0.PolyFunPow;
1087 AR.Eside = AR0.Eside;
1088 AR.Cnumlhs = AR0.Cnumlhs;
1089/*
1090 AR.MaxBracket = AR0.MaxBracket;
1091
1092 The compressbuffer contents are mainly relevant for keep brackets
1093 We should do this only if there is a keep brackets statement
1094 We may however still need the compressbuffer for expressions in the rhs.
1095*/
1096 if ( par >= 1 ) {
1097/*
1098 We may not need this %%%%% 7-apr-2006
1099*/
1100 t1 = AR.CompressBuffer; t2 = AR0.CompressBuffer;
1101 while ( t2 < AR0.CompressPointer ) *t1++ = *t2++;
1102 AR.CompressPointer = t1;
1103
1104 }
1105 else {
1106 AR.CompressPointer = AR.CompressBuffer;
1107 }
1108 if ( AR.DeferFlag ) {
1109 if ( AR.infile->handle < 0 ) {
1110 AR.infile->POfill = AR0.infile->POfill;
1111 }
1112 else {
1113/*
1114 We have to set the value of POposition to something that will
1115 force a read in the first try.
1116*/
1117 AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer;
1118 }
1119 }
1120 if ( par == 0 ) {
1121 AN.threadbuck = thr;
1122 AN.ninterms = thr->firstterm;
1123 }
1124 else if ( par == 1 ) {
1125 WORD *tstop;
1126 t1 = thr->threadbuffer; tstop = t1 + *t1;
1127 t2 = AT.WorkPointer;
1128 while ( t1 < tstop ) *t2++ = *t1++;
1129 AN.ninterms = thr->firstterm;
1130 }
1131 AN.TeInFun = 0;
1132 AN.ncmod = AC.ncmod;
1133 AT.BrackBuf = AT0.BrackBuf;
1134 AT.bracketindexflag = AT0.bracketindexflag;
1135 AN.PolyFunTodo = 0;
1136/*
1137 The relevant variables and the term are in their place.
1138 There is nothing more to do.
1139*/
1140 return(0);
1141}
1142
1143/*
1144 #] LoadOneThread :
1145 #[ BalanceRunThread :
1146*/
1161/* UNFINISHED_FEATURE_EXCL_START */
1162int BalanceRunThread(PHEAD int identity, WORD *term, WORD level)
1163{
1164 GETBIDENTITY
1165 ALLPRIVATES *BB;
1166 WORD *t, *tt;
1167 int i, *ti, *tti;
1168
1169 LoadOneThread(AT.identity,identity,0,2);
1170/*
1171 Extra loading if needed. Quantities changed in Generator.
1172 Like the level that has to be passed.
1173*/
1174 BB = AB[identity];
1175 BB->R.level = level;
1176 BB->T.TMbuff = AT.TMbuff;
1177 ti = AT.RepCount; tti = BB->T.RepCount;
1178 i = AN.RepPoint - AT.RepCount;
1179 BB->N.RepPoint = BB->T.RepCount + i;
1180 for ( ; i >= 0; i-- ) tti[i] = ti[i];
1181
1182 t = term; i = *term;
1183 tt = BB->T.WorkSpace;
1184 NCOPY(tt,t,i);
1185 BB->T.WorkPointer = tt;
1186
1187 WakeupThread(identity,HIGHERLEVELGENERATION);
1188
1189 return(0);
1190}
1191/* UNFINISHED_FEATURE_EXCL_STOP */
1192/*
1193 #] BalanceRunThread :
1194 #[ SetWorkerFiles :
1195*/
1200void SetWorkerFiles(void)
1201{
1202 int id;
1203 ALLPRIVATES *B, *B0 = AB[0];
1204 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
1205 B = AB[id];
1206 AR.infile = &(AR.Fscr[0]);
1207 AR.outfile = &(AR.Fscr[1]);
1208 AR.hidefile = &(AR.Fscr[2]);
1209 AR.infile->handle = AR0.infile->handle;
1210 AR.hidefile->handle = AR0.hidefile->handle;
1211 if ( AR.infile->handle < 0 ) {
1212 AR.infile->PObuffer = AR0.infile->PObuffer;
1213 AR.infile->POstop = AR0.infile->POstop;
1214 AR.infile->POfill = AR0.infile->POfill;
1215 AR.infile->POfull = AR0.infile->POfull;
1216 AR.infile->POsize = AR0.infile->POsize;
1217 AR.InInBuf = AR0.InInBuf;
1218 AR.infile->POposition = AR0.infile->POposition;
1219 AR.infile->filesize = AR0.infile->filesize;
1220 }
1221 else {
1222 AR.infile->PObuffer = AR.infile->wPObuffer;
1223 AR.infile->POstop = AR.infile->wPOstop;
1224 AR.infile->POfill = AR.infile->wPOfill;
1225 AR.infile->POfull = AR.infile->wPOfull;
1226 AR.infile->POsize = AR.infile->wPOsize;
1227 AR.InInBuf = 0;
1228 PUTZERO(AR.infile->POposition);
1229 }
1230/*
1231 If there is some writing, it betters happens to ones own outfile.
1232 Currently this is to be done only for InParallel.
1233 Merging of the outputs is then done by the CopyExpression routine.
1234*/
1235 {
1236 AR.outfile->PObuffer = AR.outfile->wPObuffer;
1237 AR.outfile->POstop = AR.outfile->wPOstop;
1238 AR.outfile->POfill = AR.outfile->wPOfill;
1239 AR.outfile->POfull = AR.outfile->wPOfull;
1240 AR.outfile->POsize = AR.outfile->wPOsize;
1241 PUTZERO(AR.outfile->POposition);
1242 }
1243 if ( AR.hidefile->handle < 0 ) {
1244 AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
1245 AR.hidefile->POstop = AR0.hidefile->POstop;
1246 AR.hidefile->POfill = AR0.hidefile->POfill;
1247 AR.hidefile->POfull = AR0.hidefile->POfull;
1248 AR.hidefile->POsize = AR0.hidefile->POsize;
1249 AR.InHiBuf = AR0.InHiBuf;
1250 AR.hidefile->POposition = AR0.hidefile->POposition;
1251 AR.hidefile->filesize = AR0.hidefile->filesize;
1252 }
1253 else {
1254 AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
1255 AR.hidefile->POstop = AR.hidefile->wPOstop;
1256 AR.hidefile->POfill = AR.hidefile->wPOfill;
1257 AR.hidefile->POfull = AR.hidefile->wPOfull;
1258 AR.hidefile->POsize = AR.hidefile->wPOsize;
1259 AR.InHiBuf = 0;
1260 PUTZERO(AR.hidefile->POposition);
1261 }
1262 }
1263 if ( AR0.StoreData.dirtyflag ) {
1264 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
1265 B = AB[id];
1266 AR.StoreData = AR0.StoreData;
1267 }
1268 }
1269}
1270
1271/*
1272 #] SetWorkerFiles :
1273 #[ RunThread :
1274*/
1282void *RunThread(void *dummy)
1283{
1284 WORD *term, *ttin, *tt, *ttco, *oldwork;
1285 int identity, wakeupsignal, identityretv, i, tobereleased, errorcode;
1286 ALLPRIVATES *B;
1287 THREADBUCKET *thr;
1288 POSITION *ppdef;
1289 EXPRESSIONS e;
1290 DUMMYUSE(dummy);
1291 identity = SetIdentity(&identityretv);
1292 threadpointers[identity] = pthread_self();
1293 B = InitializeOneThread(identity);
1294 while ( ( wakeupsignal = ThreadWait(identity) ) > 0 ) {
1295 switch ( wakeupsignal ) {
1296/*
1297 #[ STARTNEWEXPRESSION :
1298*/
1299 case STARTNEWEXPRESSION:
1300/*
1301 Set up the sort routines etc.
1302 Start with getting some buffers synchronized with the compiler
1303*/
1304 if ( UpdateOneThread(identity) ) {
1305/* INTERNAL_ERROR_EXCL_START */
1306 MLOCK(ErrorMessageLock);
1307 MesPrint("!>Update error in starting expression in thread %d in module %d",identity,AC.CModule);
1308 MUNLOCK(ErrorMessageLock);
1309 Terminate(-1);
1310/* INTERNAL_ERROR_EXCL_STOP */
1311 }
1312 AR.DeferFlag = AC.ComDefer;
1313 AR.sLevel = AS.sLevel;
1314 AR.MaxDum = AM.IndDum;
1315 AR.expchanged = AB[0]->R.expchanged;
1316 AR.expflags = AB[0]->R.expflags;
1317 AR.PolyFun = AB[0]->R.PolyFun;
1318 AR.PolyFunInv = AB[0]->R.PolyFunInv;
1319 AR.PolyFunType = AB[0]->R.PolyFunType;
1320 AR.PolyFunExp = AB[0]->R.PolyFunExp;
1321 AR.PolyFunVar = AB[0]->R.PolyFunVar;
1322 AR.PolyFunPow = AB[0]->R.PolyFunPow;
1323/*
1324 Now fire up the sort buffer.
1325*/
1326 NewSort(BHEAD0);
1327 break;
1328/*
1329 #] STARTNEWEXPRESSION :
1330 #[ LOWESTLEVELGENERATION :
1331*/
1332 case LOWESTLEVELGENERATION:
1333#ifdef INNERTEST
1334 if ( AC.InnerTest ) {
1335 if ( StrCmp(AC.TestValue,(UBYTE *)INNERTEST) == 0 ) {
1336 MesPrint("Testing(Worker%d): value = %s",AT.identity,AC.TestValue);
1337 }
1338 }
1339#endif
1340 e = Expressions + AR.CurExpr;
1341 thr = AN.threadbuck;
1342 ppdef = thr->deferbuffer;
1343 ttin = thr->threadbuffer;
1344 ttco = thr->compressbuffer;
1345 term = AT.WorkPointer;
1346 thr->usenum = 0;
1347 tobereleased = 0;
1348 AN.inputnumber = thr->firstterm;
1349 AN.ninterms = thr->firstterm;
1350 do {
1351 thr->usenum++; /* For if the master wants to steal the bucket */
1352 tt = term; i = *ttin;
1353 NCOPY(tt,ttin,i);
1354 AT.WorkPointer = tt;
1355 if ( AR.DeferFlag ) {
1356 tt = AR.CompressBuffer; i = *ttco;
1357 NCOPY(tt,ttco,i);
1358 AR.CompressPointer = tt;
1359 AR.DefPosition = ppdef[0]; ppdef++;
1360 }
1361 if ( thr->free == BUCKETTERMINATED ) {
1362/*
1363 The next statement allows the master to steal the bucket
1364 for load balancing purposes. We do still execute the current
1365 term, but afterwards we drop out.
1366 Once we have written the release code, we cannot use this
1367 bucket anymore. Hence the exit to the label bucketstolen.
1368*/
1369 if ( thr->usenum == thr->totnum ) {
1370 thr->free = BUCKETCOMINGFREE;
1371 }
1372 else {
1373 thr->free = BUCKETRELEASED;
1374 tobereleased = 1;
1375 }
1376 }
1377/*
1378 What if we want to steal and we set thr->free while
1379 the thread is inside the next code for a long time?
1380 if ( AT.LoadBalancing ) {
1381*/
1382 LOCK(thr->lock);
1383 thr->busy = BUCKETDOINGTERM;
1384 UNLOCK(thr->lock);
1385/*
1386 }
1387 else {
1388 thr->busy = BUCKETDOINGTERM;
1389 }
1390*/
1391 AN.RepPoint = AT.RepCount + 1;
1392
1393 if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1394 StoreTerm(BHEAD term);
1395 }
1396 else {
1397 if ( AR.DeferFlag ) {
1398 AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
1399 }
1400 else {
1401 AN.IndDum = AM.IndDum;
1402 AR.CurDum = ReNumber(BHEAD term);
1403 }
1404 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1405 if ( AN.ncmod ) {
1406 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1407 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1408 }
1409 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1410 if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
1411 MLOCK(ErrorMessageLock);
1412 MesPrint("Thread %w executing term:");
1413 PrintTerm(term,"LLG");
1414 MUNLOCK(ErrorMessageLock);
1415 }
1416 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1417 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1418 PolyFunClean(BHEAD term);
1419 }
1420 if ( Generator(BHEAD term,0) ) {
1421/* INTERNAL_ERROR_EXCL_START */
1423 MLOCK(ErrorMessageLock);
1424 MesPrint("!>Error in processing one term in thread %d in module %d",identity,AC.CModule);
1425 MUNLOCK(ErrorMessageLock);
1426 Terminate(-1);
1427/* INTERNAL_ERROR_EXCL_STOP */
1428 }
1429 AN.ninterms++;
1430 }
1431/* if ( AT.LoadBalancing ) { */
1432 LOCK(thr->lock);
1433 thr->busy = BUCKETPREPARINGTERM;
1434 UNLOCK(thr->lock);
1435/*
1436 }
1437 else {
1438 thr->busy = BUCKETPREPARINGTERM;
1439 }
1440*/
1441 if ( thr->free == BUCKETTERMINATED ) {
1442 if ( thr->usenum == thr->totnum ) {
1443 thr->free = BUCKETCOMINGFREE;
1444 }
1445 else {
1446 thr->free = BUCKETRELEASED;
1447 tobereleased = 1;
1448 }
1449 }
1450 if ( tobereleased ) goto bucketstolen;
1451 } while ( *ttin );
1452 thr->free = BUCKETCOMINGFREE;
1453bucketstolen:;
1454/* if ( AT.LoadBalancing ) { */
1455 LOCK(thr->lock);
1456 thr->busy = BUCKETTOBERELEASED;
1457 UNLOCK(thr->lock);
1458/* }
1459 else {
1460 thr->busy = BUCKETTOBERELEASED;
1461 }
1462*/
1463 AT.WorkPointer = term;
1464 break;
1465/*
1466 #] LOWESTLEVELGENERATION :
1467 #[ FINISHEXPRESSION :
1468*/
1469 case CLAIMOUTPUT:
1470 LOCK(AT.SB.MasterBlockLock[1]);
1471 break;
1472 case FINISHEXPRESSION:
1473/*
1474 Finish the sort
1475
1476 Start with claiming the first block
1477 Once we have claimed it we can let the master know that
1478 everything is all right.
1479*/
1480 LOCK(AT.SB.MasterBlockLock[1]);
1481 ThreadClaimedBlock(identity);
1482/*
1483 Entry for when we work with sortbots
1484*/
1485 /* fall through */
1486 case FINISHEXPRESSION2:
1487/*
1488 Now we may need here an fsync on the sort file
1489*/
1490 if ( AC.ThreadSortFileSynch ) {
1491 if ( AT.S0->file.handle >= 0 ) {
1492 SynchFile(AT.S0->file.handle);
1493 }
1494 }
1495 AT.SB.FillBlock = 1;
1496 AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
1497 errorcode = EndSort(BHEAD AT.S0->sBuffer,0);
1498 UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
1499 UpdateMaxSize();
1500 if ( errorcode ) {
1501 MLOCK(ErrorMessageLock);
1502 MesPrint("Error terminating sort in thread %d in module %d",identity,AC.CModule);
1503 MUNLOCK(ErrorMessageLock);
1504 Terminate(-1);
1505 }
1506 break;
1507/*
1508 #] FINISHEXPRESSION :
1509 #[ CLEANUPEXPRESSION :
1510*/
1511 case CLEANUPEXPRESSION:
1512/*
1513 Cleanup everything and wait for the next expression
1514*/
1515 if ( AR.outfile->handle >= 0 ) {
1516 CloseFile(AR.outfile->handle);
1517 AR.outfile->handle = -1;
1518 remove(AR.outfile->name);
1519 AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
1520 PUTZERO(AR.outfile->POposition);
1521 PUTZERO(AR.outfile->filesize);
1522 }
1523 else {
1524 AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
1525 PUTZERO(AR.outfile->POposition);
1526 PUTZERO(AR.outfile->filesize);
1527 }
1528 {
1529 CBUF *C = cbuf+AT.ebufnum;
1530 WORD **w, ii;
1531 if ( C->numrhs > 0 || C->numlhs > 0 ) {
1532 if ( C->rhs ) {
1533 w = C->rhs; ii = C->numrhs;
1534 do { *w++ = 0; } while ( --ii > 0 );
1535 }
1536 if ( C->lhs ) {
1537 w = C->lhs; ii = C->numlhs;
1538 do { *w++ = 0; } while ( --ii > 0 );
1539 }
1540 C->numlhs = C->numrhs = 0;
1541 ClearTree(AT.ebufnum);
1542 C->Pointer = C->Buffer;
1543 }
1544 }
1545 break;
1546/*
1547 #] CLEANUPEXPRESSION :
1548 #[ HIGHERLEVELGENERATION :
1549*/
1550 case HIGHERLEVELGENERATION:
1551/*
1552 When foliating halfway the tree.
1553 This should only be needed in a second level load balancing
1554*/
1555 term = AT.WorkSpace; AT.WorkPointer = term + *term;
1556 if ( Generator(BHEAD term,AR.level) ) {
1558 MLOCK(ErrorMessageLock);
1559 MesPrint("Error in load balancing one term at level %d in thread %d in module %d",AR.level,AT.identity,AC.CModule);
1560 MUNLOCK(ErrorMessageLock);
1561 Terminate(-1);
1562 }
1563 AT.WorkPointer = term;
1564 break;
1565/*
1566 #] HIGHERLEVELGENERATION :
1567 #[ STARTNEWMODULE :
1568*/
1569 case STARTNEWMODULE:
1570/*
1571 For resetting variables.
1572*/
1573 SpecialCleanup(B);
1574 break;
1575/*
1576 #] STARTNEWMODULE :
1577 #[ TERMINATETHREAD :
1578*/
1579 case TERMINATETHREAD:
1580 goto EndOfThread;
1581/*
1582 #] TERMINATETHREAD :
1583 #[ DOONEEXPRESSION :
1584
1585 When a thread has to do a complete (not too big) expression.
1586 The number of the expression to be done is in AR.exprtodo.
1587 The code is mostly taken from Processor. The only difference
1588 is with what to do with the output.
1589 The output should go to the scratch buffer of the worker
1590 (which is free at the right moment). If this buffer is too
1591 small we have a problem. We could write to file or give the
1592 master what we have and from now on the master has to collect
1593 pieces until things are complete.
1594 Note: this assumes that the expressions don't keep their order.
1595 If they have to keep their order, don't use this feature.
1596*/
1597 case DOONEEXPRESSION: {
1598
1599 POSITION position, outposition;
1600 FILEHANDLE *fi, *fout, *oldoutfile;
1601 LONG dd = 0;
1602 WORD oldBracketOn = AR.BracketOn;
1603 WORD *oldBrackBuf = AT.BrackBuf;
1604 WORD oldbracketindexflag = AT.bracketindexflag;
1605 WORD fromspectator = 0;
1606 e = Expressions + AR.exprtodo;
1607 i = AR.exprtodo;
1608 AR.CurExpr = i;
1609 AR.SortType = AC.SortType;
1610 AR.expchanged = 0;
1611 if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
1612 AR.BracketOn = 1;
1613 AT.BrackBuf = AM.BracketFactors;
1614 AT.bracketindexflag = 1;
1615 }
1616
1617 position = AS.OldOnFile[i];
1618 if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION
1619 || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION ) {
1620 AR.GetFile = 2; fi = AR.hidefile;
1621 }
1622 else {
1623 AR.GetFile = 0; fi = AR.infile;
1624 }
1625/*
1626 PUTZERO(fi->POposition);
1627 if ( fi->handle >= 0 ) {
1628 fi->POfill = fi->POfull = fi->PObuffer;
1629 }
1630*/
1631 SetScratch(fi,&position);
1632 term = oldwork = AT.WorkPointer;
1633 AR.CompressPointer = AR.CompressBuffer;
1634 AR.CompressPointer[0] = 0;
1635 AR.KeptInHold = 0;
1636 if ( GetTerm(BHEAD term) <= 0 ) {
1637 MLOCK(ErrorMessageLock);
1638 MesPrint("Expression %d has problems in scratchfile (t)",i);
1639 MUNLOCK(ErrorMessageLock);
1640 Terminate(-1);
1641 }
1642 if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
1643 term[3] = i;
1644 if ( term[5] < 0 ) {
1645 fromspectator = -term[5];
1646 PUTZERO(AM.SpectatorFiles[fromspectator-1].readpos);
1647 term[5] = AC.cbufnum;
1648 }
1649 PUTZERO(outposition);
1650 fout = AR.outfile;
1651 fout->POfill = fout->POfull = fout->PObuffer;
1652 fout->POposition = outposition;
1653 if ( fout->handle >= 0 ) {
1654 fout->POposition = outposition;
1655 }
1656/*
1657 The next statement is needed because we need the system
1658 to believe that the expression is at position zero for
1659 the moment. In this worker, with no memory of other expressions,
1660 it is. This is needed for when a bracket index is made
1661 because there e->onfile is an offset. Afterwards, when the
1662 expression is written to its final location in the masters
1663 output e->onfile will get its real value.
1664*/
1665 PUTZERO(e->onfile);
1666 if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) goto ProcErr;
1667
1668 AR.DeferFlag = AC.ComDefer;
1669
1670 AR.sLevel = AB[0]->R.sLevel;
1671 term = AT.WorkPointer;
1672 NewSort(BHEAD0);
1673 AR.MaxDum = AM.IndDum;
1674 AN.ninterms = 0;
1675 if ( fromspectator ) {
1676 while ( GetFromSpectator(term,fromspectator-1) ) {
1677 AT.WorkPointer = term + *term;
1678 AN.RepPoint = AT.RepCount + 1;
1679 AN.IndDum = AM.IndDum;
1680 AR.CurDum = ReNumber(BHEAD term);
1681 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1682 if ( AN.ncmod ) {
1683 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1684 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1685 }
1686 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1687 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1688 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1689 PolyFunClean(BHEAD term);
1690 }
1691 if ( Generator(BHEAD term,0) ) {
1692 LowerSortLevel(); goto ProcErr;
1693 }
1694 }
1695 }
1696 else {
1697 while ( GetTerm(BHEAD term) ) {
1698 SeekScratch(fi,&position);
1699 AN.ninterms++; dd = AN.deferskipped;
1700 if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1701 StoreTerm(BHEAD term);
1702 }
1703 else {
1704 if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
1705 if ( GetMoreTerms(term) < 0 ) {
1706 LowerSortLevel(); goto ProcErr;
1707 }
1708 SeekScratch(fi,&position);
1709 }
1710 AT.WorkPointer = term + *term;
1711 AN.RepPoint = AT.RepCount + 1;
1712 if ( AR.DeferFlag ) {
1713 AR.CurDum = AN.IndDum = Expressions[AR.exprtodo].numdummies;
1714 }
1715 else {
1716 AN.IndDum = AM.IndDum;
1717 AR.CurDum = ReNumber(BHEAD term);
1718 }
1719 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1720 if ( AN.ncmod ) {
1721 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1722 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1723 }
1724 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1725 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1726 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1727 PolyFunClean(BHEAD term);
1728 }
1729 if ( Generator(BHEAD term,0) ) {
1730 LowerSortLevel(); goto ProcErr;
1731 }
1732 AN.ninterms += dd;
1733 }
1734 SetScratch(fi,&position);
1735 if ( fi == AR.hidefile ) {
1736 AR.InHiBuf = (fi->POfull-fi->PObuffer)
1737 -DIFBASE(position,fi->POposition)/sizeof(WORD);
1738 }
1739 else {
1740 AR.InInBuf = (fi->POfull-fi->PObuffer)
1741 -DIFBASE(position,fi->POposition)/sizeof(WORD);
1742 }
1743 }
1744 }
1745 AN.ninterms += dd;
1746 if ( EndSort(BHEAD AT.S0->sBuffer,0) < 0 ) goto ProcErr;
1747 e->numdummies = AR.MaxDum - AM.IndDum;
1748 AR.BracketOn = oldBracketOn;
1749 AT.BrackBuf = oldBrackBuf;
1750 if ( ( e->vflags & TOBEFACTORED ) != 0 )
1752 else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
1753 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
1755 if ( AT.S0->TermsLeft ) e->vflags &= ~ISZERO;
1756 else e->vflags |= ISZERO;
1757 if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
1758 if ( AT.S0->TermsLeft ) AR.expflags |= ISZERO;
1759 if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;
1760 AR.GetFile = 0;
1761 AT.bracketindexflag = oldbracketindexflag;
1762/*
1763 Now copy the whole thing from fout to AR0.outfile
1764 Do this in one go to keep the lock occupied as short as possible
1765*/
1766 SeekScratch(fout,&outposition);
1767 LOCK(AS.outputslock);
1768 oldoutfile = AB[0]->R.outfile;
1769 if ( e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
1770 AB[0]->R.outfile = AB[0]->R.hidefile;
1771 }
1772 SeekScratch(AB[0]->R.outfile,&position);
1773 e->onfile = position;
1774 if ( CopyExpression(fout,AB[0]->R.outfile) < 0 ) {
1775 AB[0]->R.outfile = oldoutfile;
1776 UNLOCK(AS.outputslock);
1777 MLOCK(ErrorMessageLock);
1778 MesPrint("Error copying output of 'InParallel' expression to master. Thread: %d",identity);
1779 MUNLOCK(ErrorMessageLock);
1780 goto ProcErr;
1781 }
1782 AB[0]->R.outfile = oldoutfile;
1783 AB[0]->R.expflags = AR.expflags;
1784 UNLOCK(AS.outputslock);
1785
1786 if ( fout->handle >= 0 ) { /* Now get rid of the file */
1787 CloseFile(fout->handle);
1788 fout->handle = -1;
1789 remove(fout->name);
1790 PUTZERO(fout->POposition);
1791 PUTZERO(fout->filesize);
1792 fout->POfill = fout->POfull = fout->PObuffer;
1793 }
1794 UpdateMaxSize();
1795
1796 AT.WorkPointer = oldwork;
1797
1798 } break;
1799/*
1800 #] DOONEEXPRESSION :
1801 #[ DOBRACKETS :
1802
1803 In case we have a bracket index we can have the worker treat
1804 one or more of the entries in the bracket index.
1805 The advantage is that identical terms will meet each other
1806 sooner in the sorting and hence fewer compares will be needed.
1807 Also this way the master doesn't need to fill the buckets.
1808 The main problem is the load balancing which can become very
1809 bad when there is a long tail without things outside the bracket.
1810
1811 We get sent:
1812 1: The number of the first bracket to be done
1813 2: The number of the last bracket to be done
1814*/
1815 case DOBRACKETS: {
1816 BRACKETINFO *binfo;
1817 BRACKETINDEX *bi;
1818 FILEHANDLE *fi;
1819 POSITION stoppos,where;
1820 e = Expressions + AR.CurExpr;
1821 binfo = e->bracketinfo;
1822 thr = AN.threadbuck;
1823 bi = &(binfo->indexbuffer[thr->firstbracket]);
1824 if ( AR.GetFile == 2 ) fi = AR.hidefile;
1825 else fi = AR.infile;
1826 where = bi->start;
1827 ADD2POS(where,AS.OldOnFile[AR.CurExpr]);
1828 SetScratch(fi,&(where));
1829 stoppos = binfo->indexbuffer[thr->lastbracket].next;
1830 ADD2POS(stoppos,AS.OldOnFile[AR.CurExpr]);
1831 AN.ninterms = thr->firstterm;
1832/*
1833 Now we have to put the 'value' of the bracket in the
1834 Compress buffer.
1835*/
1836 ttco = AR.CompressBuffer;
1837 tt = binfo->bracketbuffer + bi->bracket;
1838 i = *tt;
1839 NCOPY(ttco,tt,i)
1840 AR.CompressPointer = ttco;
1841 term = AT.WorkPointer;
1842 while ( GetTerm(BHEAD term) ) {
1843 SeekScratch(fi,&where);
1844 AT.WorkPointer = term + *term;
1845 AN.IndDum = AM.IndDum;
1846 AR.CurDum = ReNumber(BHEAD term);
1847 if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1848 if ( AN.ncmod ) {
1849 if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1850 else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1851 }
1852 else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1853 if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1854 && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
1855 PolyFunClean(BHEAD term);
1856 }
1857 if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
1858 MLOCK(ErrorMessageLock);
1859 MesPrint("Thread %w executing term:");
1860 PrintTerm(term,"DoBrackets");
1861 MUNLOCK(ErrorMessageLock);
1862 }
1863 AT.WorkPointer = term + *term;
1864 if ( Generator(BHEAD term,0) ) {
1866 MLOCK(ErrorMessageLock);
1867 MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
1868 MUNLOCK(ErrorMessageLock);
1869 Terminate(-1);
1870 }
1871 AN.ninterms++;
1872 SetScratch(fi,&(where));
1873 if ( ISGEPOS(where,stoppos) ) break;
1874 }
1875 AT.WorkPointer = term;
1876 thr->free = BUCKETCOMINGFREE;
1877 break;
1878 }
1879/*
1880 #] DOBRACKETS :
1881 #[ CLEARCLOCK :
1882
1883 The program only comes here after a .clear
1884*/
1885 case CLEARCLOCK:
1886/* LOCK(clearclocklock); */
1887 sumtimerinfo[identity] += TimeCPU(1);
1888 timerinfo[identity] = TimeCPU(0);
1889/* UNLOCK(clearclocklock); */
1890 break;
1891/*
1892 #] CLEARCLOCK :
1893 #[ MCTSEXPANDTREE :
1894*/
1895 case MCTSEXPANDTREE:
1896 AT.optimtimes = AB[0]->T.optimtimes;
1897 find_Horner_MCTS_expand_tree();
1898 break;
1899/*
1900 #] MCTSEXPANDTREE :
1901 #[ OPTIMIZEEXPRESSION :
1902*/
1903 case OPTIMIZEEXPRESSION:
1905 break;
1906/*
1907 #] OPTIMIZEEXPRESSION :
1908*/
1909 default:
1910/* INTERNAL_ERROR_EXCL_START */
1911 MLOCK(ErrorMessageLock);
1912 MesPrint("!>Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
1913 MUNLOCK(ErrorMessageLock);
1914 Terminate(-1);
1915 break;
1916/* INTERNAL_ERROR_EXCL_STOP */
1917 }
1918 /* we need the following update in case we are using checkpoints. then we
1919 need to readjust the clocks when recovering using this information */
1920 timerinfo[identity] = TimeCPU(1);
1921 }
1922EndOfThread:;
1923/*
1924 This is the end of the thread. We cleanup and exit.
1925 If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
1926*/
1927#ifdef WITHFLINT
1928 flint_final_cleanup_thread();
1929#endif
1930 FinalizeOneThread(identity);
1931 return(0);
1932ProcErr:
1933 Terminate(-1);
1934 return(0);
1935}
1936
1937/*
1938 #] RunThread :
1939 #[ RunSortBot :
1940*/
1949void *RunSortBot(void *dummy)
1950{
1951 int identity, wakeupsignal, identityretv;
1952 ALLPRIVATES *B, *BB;
1953 DUMMYUSE(dummy);
1954 identity = SetIdentity(&identityretv);
1955 threadpointers[identity] = pthread_self();
1956 B = InitializeOneThread(identity);
1957 while ( ( wakeupsignal = SortBotWait(identity) ) > 0 ) {
1958 switch ( wakeupsignal ) {
1959/*
1960 #[ INISORTBOT :
1961*/
1962 case INISORTBOT:
1963 AR.CompressBuffer = AB[0]->R.CompressBuffer;
1964 AR.ComprTop = AB[0]->R.ComprTop;
1965 AR.CompressPointer = AB[0]->R.CompressPointer;
1966 AR.CurExpr = AB[0]->R.CurExpr;
1967 AR.PolyFun = AB[0]->R.PolyFun;
1968 AR.PolyFunInv = AB[0]->R.PolyFunInv;
1969 AR.PolyFunType = AB[0]->R.PolyFunType;
1970 AR.PolyFunExp = AB[0]->R.PolyFunExp;
1971 AR.PolyFunVar = AB[0]->R.PolyFunVar;
1972 AR.PolyFunPow = AB[0]->R.PolyFunPow;
1973 AR.SortType = AC.SortType;
1974 if ( AR.PolyFun == 0 ) { AT.SS->PolyFlag = 0; }
1975 else if ( AR.PolyFunType == 1 ) { AT.SS->PolyFlag = 1; }
1976 else if ( AR.PolyFunType == 2 ) {
1977 if ( AR.PolyFunExp == 2
1978 || AR.PolyFunExp == 3 ) AT.SS->PolyFlag = 1;
1979 else AT.SS->PolyFlag = 2;
1980 }
1981 AT.SS->PolyWise = 0;
1982 AN.ncmod = AC.ncmod;
1983 LOCK(AT.SB.MasterBlockLock[1]);
1984 BB = AB[AT.SortBotIn1];
1985 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
1986 if ( AT.SortBotIn2 >= 0 ) {
1987 BB = AB[AT.SortBotIn2];
1988 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
1989 }
1990 AT.SB.FillBlock = 1;
1991 AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
1992 SETBASEPOSITION(AN.theposition,0);
1993 // Reset the sortbot comparison count
1994 AT.SS->verbComparisons = 0;
1995 // Reset the maximal term size count
1996 AT.SS->verbMaxTermSize = 0;
1997 break;
1998/*
1999 #] INISORTBOT :
2000 #[ RUNSORTBOT :
2001*/
2002 case RUNSORTBOT:
2003 SortBotMerge(B);
2004 break;
2005/*
2006 #] RUNSORTBOT :
2007 #[ TERMINATETHREAD :
2008*/
2009 case TERMINATETHREAD:
2010 goto EndOfThread;
2011/*
2012 #] TERMINATETHREAD :
2013 #[ CLEARCLOCK :
2014
2015 The program only comes here after a .clear
2016*/
2017 case CLEARCLOCK:
2018/* LOCK(clearclocklock); */
2019 sumtimerinfo[identity] += TimeCPU(1);
2020 timerinfo[identity] = TimeCPU(0);
2021/* UNLOCK(clearclocklock); */
2022 break;
2023/*
2024 #] CLEARCLOCK :
2025*/
2026 default:
2027/* INTERNAL_ERROR_EXCL_START */
2028 MLOCK(ErrorMessageLock);
2029 MesPrint("!>Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
2030 MUNLOCK(ErrorMessageLock);
2031 Terminate(-1);
2032 break;
2033/* INTERNAL_ERROR_EXCL_STOP */
2034 }
2035 }
2036EndOfThread:;
2037/*
2038 This is the end of the thread. We cleanup and exit.
2039 If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
2040*/
2041#ifdef WITHFLINT
2042 flint_final_cleanup_thread();
2043#endif
2044 FinalizeOneThread(identity);
2045 return(0);
2046}
2047
2048
2049/*
2050 #] RunSortBot :
2051 #[ IAmAvailable :
2052*/
2064void IAmAvailable(int identity)
2065{
2066 int top;
2067 LOCK(availabilitylock);
2068 top = topofavailables;
2069 listofavailables[topofavailables++] = identity;
2070 if ( top == 0 ) {
2071 UNLOCK(availabilitylock);
2072 LOCK(wakeupmasterlock);
2073 wakeupmaster = identity;
2074 pthread_cond_signal(&wakeupmasterconditions);
2075 UNLOCK(wakeupmasterlock);
2076 }
2077 else {
2078 UNLOCK(availabilitylock);
2079 }
2080}
2081
2082/*
2083 #] IAmAvailable :
2084 #[ GetAvailableThread :
2085*/
2094int GetAvailableThread(void)
2095{
2096 int retval = -1;
2097 LOCK(availabilitylock);
2098 if ( topofavailables > 0 ) retval = listofavailables[--topofavailables];
2099 UNLOCK(availabilitylock);
2100 if ( retval >= 0 ) {
2101/*
2102 Make sure the thread is indeed waiting and not between
2103 saying that it is available and starting to wait.
2104*/
2105 LOCK(wakeuplocks[retval]);
2106 UNLOCK(wakeuplocks[retval]);
2107 }
2108 return(retval);
2109}
2110
2111/*
2112 #] GetAvailableThread :
2113 #[ ConditionalGetAvailableThread :
2114*/
2122int ConditionalGetAvailableThread(void)
2123{
2124 int retval = -1;
2125 if ( topofavailables > 0 ) {
2126 LOCK(availabilitylock);
2127 if ( topofavailables > 0 ) {
2128 retval = listofavailables[--topofavailables];
2129 }
2130 UNLOCK(availabilitylock);
2131 if ( retval >= 0 ) {
2132/*
2133 Make sure the thread is indeed waiting and not between
2134 saying that it is available and starting to wait.
2135*/
2136 LOCK(wakeuplocks[retval]);
2137 UNLOCK(wakeuplocks[retval]);
2138 }
2139 }
2140 return(retval);
2141}
2142
2143/*
2144 #] ConditionalGetAvailableThread :
2145 #[ GetThread :
2146*/
2156int GetThread(int identity)
2157{
2158 int retval = -1, j;
2159 LOCK(availabilitylock);
2160 for ( j = 0; j < topofavailables; j++ ) {
2161 if ( identity == listofavailables[j] ) break;
2162 }
2163 if ( j < topofavailables ) {
2164 --topofavailables;
2165 for ( ; j < topofavailables; j++ ) {
2166 listofavailables[j] = listofavailables[j+1];
2167 }
2168 retval = identity;
2169 }
2170 UNLOCK(availabilitylock);
2171 return(retval);
2172}
2173
2174/*
2175 #] GetThread :
2176 #[ ThreadWait :
2177*/
2187int ThreadWait(int identity)
2188{
2189 int retval, top, j;
2190 LOCK(wakeuplocks[identity]);
2191 LOCK(availabilitylock);
2192 top = topofavailables;
2193 for ( j = topofavailables; j > 0; j-- )
2194 listofavailables[j] = listofavailables[j-1];
2195 listofavailables[0] = identity;
2196 topofavailables++;
2197 if ( top == 0 || topofavailables == numberofworkers ) {
2198 UNLOCK(availabilitylock);
2199 LOCK(wakeupmasterlock);
2200 wakeupmaster = identity;
2201 pthread_cond_signal(&wakeupmasterconditions);
2202 UNLOCK(wakeupmasterlock);
2203 }
2204 else {
2205 UNLOCK(availabilitylock);
2206 }
2207 while ( wakeup[identity] == 0 ) {
2208 pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
2209 }
2210 retval = wakeup[identity];
2211 wakeup[identity] = 0;
2212 UNLOCK(wakeuplocks[identity]);
2213 return(retval);
2214}
2215
2216/*
2217 #] ThreadWait :
2218 #[ SortBotWait :
2219*/
2220
2230int SortBotWait(int identity)
2231{
2232 int retval;
2233 LOCK(wakeuplocks[identity]);
2234 LOCK(availabilitylock);
2235 topsortbotavailables++;
2236 if ( topsortbotavailables >= GetNumberOfSortBots(numberofworkers) ) {
2237 UNLOCK(availabilitylock);
2238 LOCK(wakeupsortbotlock);
2239 wakeupmaster = identity;
2240 pthread_cond_signal(&wakeupsortbotconditions);
2241 UNLOCK(wakeupsortbotlock);
2242 }
2243 else {
2244 UNLOCK(availabilitylock);
2245 }
2246 while ( wakeup[identity] == 0 ) {
2247 pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
2248 }
2249 retval = wakeup[identity];
2250 wakeup[identity] = 0;
2251 UNLOCK(wakeuplocks[identity]);
2252 return(retval);
2253}
2254
2255
2256/*
2257 #] SortBotWait :
2258 #[ ThreadClaimedBlock :
2259*/
2270int ThreadClaimedBlock(int identity)
2271{
2272 LOCK(availabilitylock);
2273 numberclaimed++;
2274 if ( numberclaimed >= numberofworkers ) {
2275 UNLOCK(availabilitylock);
2276 LOCK(wakeupmasterlock);
2277 wakeupmaster = identity;
2278 pthread_cond_signal(&wakeupmasterconditions);
2279 UNLOCK(wakeupmasterlock);
2280 }
2281 else {
2282 UNLOCK(availabilitylock);
2283 }
2284 return(0);
2285}
2286
2287/*
2288 #] ThreadClaimedBlock :
2289 #[ MasterWait :
2290*/
2298int MasterWait(void)
2299{
2300 int retval;
2301 LOCK(wakeupmasterlock);
2302 while ( wakeupmaster == 0 ) {
2303 pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2304 }
2305 retval = wakeupmaster;
2306 wakeupmaster = 0;
2307 UNLOCK(wakeupmasterlock);
2308 return(retval);
2309}
2310
2311/*
2312 #] MasterWait :
2313 #[ MasterWaitThread :
2314*/
2321int MasterWaitThread(int identity)
2322{
2323 int retval;
2324 LOCK(wakeupmasterthreadlocks[identity]);
2325 while ( wakeupmasterthread[identity] == 0 ) {
2326 pthread_cond_wait(&(wakeupmasterthreadconditions[identity])
2327 ,&(wakeupmasterthreadlocks[identity]));
2328 }
2329 retval = wakeupmasterthread[identity];
2330 wakeupmasterthread[identity] = 0;
2331 UNLOCK(wakeupmasterthreadlocks[identity]);
2332 return(retval);
2333}
2334
2335/*
2336 #] MasterWaitThread :
2337 #[ MasterWaitAll :
2338*/
2345void MasterWaitAll(void)
2346{
2347 LOCK(wakeupmasterlock);
2348 while ( topofavailables < numberofworkers ) {
2349 pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2350 }
2351 UNLOCK(wakeupmasterlock);
2352 return;
2353}
2354
2355/*
2356 #] MasterWaitAll :
2357 #[ MasterWaitAllSortBots :
2358*/
2359
2360
2366void MasterWaitAllSortBots(void)
2367{
2368 LOCK(wakeupsortbotlock);
2369 while ( topsortbotavailables < GetNumberOfSortBots(numberofworkers) ) {
2370 pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
2371 }
2372 UNLOCK(wakeupsortbotlock);
2373 return;
2374}
2375
2376
2377/*
2378 #] MasterWaitAllSortBots :
2379 #[ MasterWaitAllBlocks :
2380*/
2387void MasterWaitAllBlocks(void)
2388{
2389 LOCK(wakeupmasterlock);
2390 while ( numberclaimed < numberofworkers ) {
2391 pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2392 }
2393 UNLOCK(wakeupmasterlock);
2394 return;
2395}
2396
2397/*
2398 #] MasterWaitAllBlocks :
2399 #[ WakeupThread :
2400*/
2409void WakeupThread(int identity, int signalnumber)
2410{
2411 if ( signalnumber == 0 ) {
2412/* INTERNAL_ERROR_EXCL_START */
2413 MLOCK(ErrorMessageLock);
2414 MesPrint("!>Illegal wakeup signal for thread %d",identity);
2415 MUNLOCK(ErrorMessageLock);
2416 Terminate(-1);
2417/* INTERNAL_ERROR_EXCL_STOP */
2418 }
2419 LOCK(wakeuplocks[identity]);
2420 wakeup[identity] = signalnumber;
2421 pthread_cond_signal(&(wakeupconditions[identity]));
2422 UNLOCK(wakeuplocks[identity]);
2423}
2424
2425/*
2426 #] WakeupThread :
2427 #[ WakeupMasterFromThread :
2428*/
2437void WakeupMasterFromThread(int identity, int signalnumber)
2438{
2439 if ( signalnumber == 0 ) {
2440/* INTERNAL_ERROR_EXCL_START */
2441 MLOCK(ErrorMessageLock);
2442 MesPrint("!>Illegal wakeup signal for master %d",identity);
2443 MUNLOCK(ErrorMessageLock);
2444 Terminate(-1);
2445/* INTERNAL_ERROR_EXCL_STOP */
2446 }
2447 LOCK(wakeupmasterthreadlocks[identity]);
2448 wakeupmasterthread[identity] = signalnumber;
2449 pthread_cond_signal(&(wakeupmasterthreadconditions[identity]));
2450 UNLOCK(wakeupmasterthreadlocks[identity]);
2451}
2452
2453/*
2454 #] WakeupMasterFromThread :
2455 #[ SendOneBucket :
2456*/
2462int SendOneBucket(int type)
2463{
2464 ALLPRIVATES *B0 = AB[0];
2465 THREADBUCKET *thr = 0;
2466 int j, k, id;
2467 for ( j = 0; j < numthreadbuckets; j++ ) {
2468 if ( threadbuckets[j]->free == BUCKETFILLED ) {
2469 thr = threadbuckets[j];
2470 for ( k = j+1; k < numthreadbuckets; k++ )
2471 threadbuckets[k-1] = threadbuckets[k];
2472 threadbuckets[numthreadbuckets-1] = thr;
2473 break;
2474 }
2475 }
2476 AN0.ninterms++;
2477 while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2478/*
2479 Prepare the thread. Give it the term and variables.
2480*/
2481 LoadOneThread(0,id,thr,0);
2482 thr->busy = BUCKETASSIGNED;
2483 thr->free = BUCKETINUSE;
2484 numberoffullbuckets--;
2485/*
2486 And signal the thread to run.
2487 Form now on we may only interfere with this bucket
2488 1: after it has been marked BUCKETCOMINGFREE
2489 2: when thr->busy == BUCKETDOINGTERM and then only when protected by
2490 thr->lock. This would be for load balancing.
2491*/
2492 WakeupThread(id,type);
2493/* AN0.ninterms += thr->ddterms; */
2494 return(0);
2495}
2496
2497/*
2498 #] SendOneBucket :
2499 #[ InParallelProcessor :
2500*/
2520int InParallelProcessor(void)
2521{
2522 GETIDENTITY
2523 int i, id, retval = 0, num = 0;
2524 EXPRESSIONS e;
2525 if ( numberofworkers >= 2 ) {
2526 SetWorkerFiles();
2527 for ( i = 0; i < NumExpressions; i++ ) {
2528 e = Expressions+i;
2529 if ( e->partodo <= 0 ) continue;
2530 if ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION
2531 || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION
2532 || e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
2533 }
2534 else {
2535 e->partodo = 0;
2536 continue;
2537 }
2538 if ( e->counter == 0 ) { /* Expression with zero terms */
2539 e->partodo = 0;
2540 continue;
2541 }
2542/*
2543 This expression should go to an idle worker
2544*/
2545 while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2546 LoadOneThread(0,id,0,-1);
2547 AB[id]->R.exprtodo = i;
2548 WakeupThread(id,DOONEEXPRESSION);
2549 num++;
2550 }
2551/*
2552 Now we have to wait for all workers to finish
2553*/
2554 if ( num > 0 ) MasterWaitAll();
2555
2556 if ( AC.CollectFun ) AR.DeferFlag = 0;
2557 }
2558 else {
2559 for ( i = 0; i < NumExpressions; i++ ) {
2560 Expressions[i].partodo = 0;
2561 }
2562 }
2563 return(retval);
2564}
2565
2566/*
2567 #] InParallelProcessor :
2568 #[ ThreadsProcessor :
2569*/
2594int ThreadsProcessor(EXPRESSIONS e, WORD LastExpression, WORD fromspectator)
2595{
2596 ALLPRIVATES *B0 = AB[0], *B = B0;
2597 int id, oldgzipCompress, endofinput = 0, j, still, k, defcount = 0, bra = 0, first = 1;
2598 LONG dd = 0, ddd, thrbufsiz, thrbufsiz0, thrbufsiz2, numbucket = 0, numpasses;
2599 LONG num, i;
2600 WORD *oldworkpointer = AT0.WorkPointer, *tt, *ttco = 0, *t1 = 0, ter, *tstop = 0, *t2;
2601 THREADBUCKET *thr = 0;
2602 FILEHANDLE *oldoutfile = AR0.outfile;
2603 GETTERM GetTermP = &GetTerm;
2604 POSITION eonfile = AS.OldOnFile[e-Expressions];
2605 numberoffullbuckets = 0;
2606/*
2607 Start up all threads. The lock needs to be around the whole loop
2608 to keep processes from terminating quickly and putting themselves
2609 in the list of available threads again.
2610*/
2611 AM.tracebackflag = 1;
2612
2613 AS.sLevel = AR0.sLevel;
2614 LOCK(availabilitylock);
2615 topofavailables = 0;
2616 for ( id = 1; id <= numberofworkers; id++ ) {
2617 WakeupThread(id,STARTNEWEXPRESSION);
2618 }
2619 UNLOCK(availabilitylock);
2620 NewSort(BHEAD0);
2621 AN0.ninterms = 1;
2622/*
2623 Now for redefine
2624*/
2625 if ( AC.numpfirstnum > 0 ) {
2626 for ( j = 0; j < AC.numpfirstnum; j++ ) {
2627 AC.inputnumbers[j] = -1;
2628 }
2629 }
2630 MasterWaitAll();
2631/*
2632 Determine a reasonable bucketsize.
2633 This is based on the value of AC.ThreadBucketSize and the number
2634 of terms. We want at least 5 buckets per worker at the moment.
2635 Some research should show whether this is reasonable.
2636
2637 The number of terms in the expression is in e->counter
2638*/
2639 thrbufsiz2 = thrbufsiz = AC.ThreadBucketSize-1;
2640 /* CopySpectator expressions have a one-term expression prototype in the
2641 * scratch file, regardless of how many terms the spectator contains. Don't
2642 * use this prototype to determine bucket size, or we'll end up with single-term
2643 * buckets and bad performance. Just use thrbufsiz in this case. */
2644 if ( ! fromspectator && ( e->counter / ( numberofworkers * 5 ) ) < thrbufsiz ) {
2645 thrbufsiz = e->counter / ( numberofworkers * 5 ) - 1;
2646 if ( thrbufsiz < 0 ) thrbufsiz = 0;
2647 }
2648 thrbufsiz0 = thrbufsiz;
2649 numpasses = 5; /* this is just for trying */
2650 thrbufsiz = thrbufsiz0 / (2 << numpasses);
2651/*
2652 Mark all buckets as free and take the first.
2653*/
2654 for ( j = 0; j < numthreadbuckets; j++ )
2655 threadbuckets[j]->free = BUCKETFREE;
2656 thr = threadbuckets[0];
2657/*
2658 #[ Whole brackets :
2659
2660 First we look whether we have to work with entire brackets
2661 This is the case when there is a non-NULL address in e->bracketinfo.
2662 Of course we shouldn't have interference from a collect or keep statement.
2663*/
2664#ifdef WHOLEBRACKETS
2665 if ( e->bracketinfo && AC.CollectFun == 0 && AR0.DeferFlag == 0 ) {
2666 FILEHANDLE *curfile;
2667 int didone = 0;
2668 LONG num, n;
2669 AN0.expr = e;
2670 for ( n = 0; n < e->bracketinfo->indexfill; n++ ) {
2671 num = TreatIndexEntry(B0,n);
2672 if ( num > 0 ) {
2673 didone = 1;
2674/*
2675 This bracket can be sent off.
2676 1: Look for an empty bucket
2677*/
2678ReTry:;
2679 for ( j = 0; j < numthreadbuckets; j++ ) {
2680 switch ( threadbuckets[j]->free ) {
2681 case BUCKETFREE:
2682 thr = threadbuckets[j];
2683 goto Found1;
2684 case BUCKETCOMINGFREE:
2685 thr = threadbuckets[j];
2686 thr->free = BUCKETFREE;
2687 for ( k = j+1; k < numthreadbuckets; k++ )
2688 threadbuckets[k-1] = threadbuckets[k];
2689 threadbuckets[numthreadbuckets-1] = thr;
2690 j--;
2691 break;
2692 default:
2693 break;
2694 }
2695 }
2696Found1:;
2697 if ( j < numthreadbuckets ) {
2698/*
2699 Found an empty bucket. Fill it.
2700*/
2701 thr->firstbracket = n;
2702 thr->lastbracket = n + num - 1;
2703 thr->type = BUCKETDOINGBRACKET;
2704 thr->free = BUCKETFILLED;
2705 thr->firstterm = AN0.ninterms;
2706 for ( j = n; j < n+num; j++ ) {
2707 AN0.ninterms += e->bracketinfo->indexbuffer[j].termsinbracket;
2708 }
2709 n += num-1;
2710 numberoffullbuckets++;
2711 if ( topofavailables > 0 ) {
2712 SendOneBucket(DOBRACKETS);
2713 }
2714 }
2715/*
2716 All buckets are in use.
2717 Look/wait for an idle worker. Give it a bucket.
2718 After that, retry for a bucket
2719*/
2720 else {
2721 while ( topofavailables <= 0 ) {
2722 MasterWait();
2723 }
2724 SendOneBucket(DOBRACKETS);
2725 goto ReTry;
2726 }
2727 }
2728 }
2729 if ( didone ) {
2730/*
2731 And now put the input back in the original position.
2732*/
2733 switch ( e->status ) {
2734 case UNHIDELEXPRESSION:
2735 case UNHIDEGEXPRESSION:
2736 case DROPHLEXPRESSION:
2737 case DROPHGEXPRESSION:
2738 case HIDDENLEXPRESSION:
2739 case HIDDENGEXPRESSION:
2740 curfile = AR0.hidefile;
2741 break;
2742 default:
2743 curfile = AR0.infile;
2744 break;
2745 }
2746 SetScratch(curfile,&eonfile);
2747 GetTerm(B0,AT0.WorkPointer);
2748/*
2749 Now we point the GetTerm that is used to the one that is selective
2750*/
2751 GetTermP = &GetTerm2;
2752/*
2753 Next wait till there is a bucket available and initialize thr to it.
2754*/
2755 for(;;) {
2756 for ( j = 0; j < numthreadbuckets; j++ ) {
2757 switch ( threadbuckets[j]->free ) {
2758 case BUCKETFREE:
2759 thr = threadbuckets[j];
2760 goto Found2;
2761 case BUCKETCOMINGFREE:
2762 thr = threadbuckets[j];
2763 thr->free = BUCKETFREE;
2764 for ( k = j+1; k < numthreadbuckets; k++ )
2765 threadbuckets[k-1] = threadbuckets[k];
2766 threadbuckets[numthreadbuckets-1] = thr;
2767 j--;
2768 break;
2769 default:
2770 break;
2771 }
2772 }
2773 while ( topofavailables <= 0 ) {
2774 MasterWait();
2775 }
2776 while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
2777 SendOneBucket(DOBRACKETS);
2778 }
2779 }
2780Found2:;
2781 while ( numberoffullbuckets > 0 ) {
2782 while ( topofavailables <= 0 ) {
2783 MasterWait();
2784 }
2785 while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
2786 SendOneBucket(DOBRACKETS);
2787 }
2788 }
2789/*
2790 Disable the 'warming up' with smaller buckets.
2791
2792 numpasses = 0;
2793 thrbufsiz = thrbufsiz0;
2794*/
2795 AN0.lastinindex = -1;
2796 }
2797 MasterWaitAll();
2798 }
2799#endif
2800/*
2801 #] Whole brackets :
2802
2803 Now the loop to start a bucket
2804*/
2805 for(;;) {
2806 if ( fromspectator ) {
2807 ter = GetFromSpectator(thr->threadbuffer,fromspectator-1);
2808 if ( ter == 0 ) fromspectator = 0;
2809 }
2810 else {
2811 ter = GetTermP(B0,thr->threadbuffer);
2812/*
2813 At this point we could check whether the input term is
2814 just an expression that resides in a scratch file.
2815 If this is the case we should store the current input info
2816 (file and buffer content) and redirect the input.
2817 At the end we can go back to where we were.
2818 There are two possibilities: we are in the same scratchfile
2819 as the main input and the other expression is still in the
2820 input buffer, or we have to do some reading. The reading is
2821 of course done in GetTerm.
2822
2823 How to set this up can also be studied in TestSub (in file proces.c)
2824 where it checks for EXPRESSION.
2825*/
2826 }
2827 if ( ter < 0 ) break;
2828 if ( ter == 0 ) { endofinput = 1; goto Finalize; }
2829 dd = AN0.deferskipped;
2830 if ( AR0.DeferFlag ) {
2831 defcount = 0;
2832 thr->deferbuffer[defcount++] = AR0.DefPosition;
2833 ttco = thr->compressbuffer; t1 = AR0.CompressBuffer; j = *t1;
2834 while ( thr->compressbuffersize <= j ) {
2835 // the compressbuffer is not large enough!
2836 WORD *top = thr->compressbuffer+thr->compressbuffersize;
2837 DoubleBuffer((void**)&(thr->compressbuffer),(void**)&(top),
2838 sizeof(*(thr->compressbuffer)), "double compressbuffer");
2839 ttco = thr->compressbuffer;
2840 thr->compressbuffersize *= 2;
2841 }
2842 NCOPY(ttco,t1,j);
2843 }
2844 else if ( first && ( AC.CollectFun == 0 ) ) { /* Brackets ? */
2845 first = 0;
2846 t1 = tstop = thr->threadbuffer;
2847 tstop += *tstop; tstop -= ABS(tstop[-1]);
2848 t1++;
2849 while ( t1 < tstop ) {
2850 if ( t1[0] == HAAKJE ) { bra = 1; break; }
2851 t1 += t1[1];
2852 }
2853 t1 = thr->threadbuffer;
2854 }
2855/*
2856 Check whether we have a collect,function going. If so execute it.
2857*/
2858 if ( AC.CollectFun && *(thr->threadbuffer) < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
2859 if ( ( dd = GetMoreTerms(thr->threadbuffer) ) < 0 ) {
2860 LowerSortLevel(); goto ProcErr;
2861 }
2862 }
2863/*
2864 Check whether we have a priority task:
2865*/
2866 if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2867/*
2868 Now put more terms in the bucket. Position tt after the first term
2869*/
2870 tt = thr->threadbuffer; tt += *tt;
2871 thr->totnum = 1;
2872 thr->usenum = 0;
2873/*
2874 Next we worry about the 'slow startup' in which we make the initial
2875 buckets smaller, so that we get all threads busy as soon as possible.
2876*/
2877 if ( numpasses > 0 ) {
2878 numbucket++;
2879 if ( numbucket >= numberofworkers ) {
2880 numbucket = 0;
2881 numpasses--;
2882 if ( numpasses == 0 ) thrbufsiz = thrbufsiz0;
2883 else thrbufsiz = thrbufsiz0 / (2 << numpasses);
2884 }
2885 thrbufsiz2 = thrbufsiz + thrbufsiz/5; /* for completing brackets */
2886 }
2887/*
2888 we have already 1+dd terms
2889*/
2890 while ( ( dd < thrbufsiz ) &&
2891 ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer/((LONG)sizeof(WORD)) - 2 ) ) {
2892/*
2893 First check:
2894*/
2895 if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2896/*
2897 There is room in the bucket. Fill yet another term.
2898*/
2899 if ( ( fromspectator
2900 ? GetFromSpectator(tt,fromspectator-1)
2901 : GetTermP(B0,tt) ) == 0 ) { endofinput = 1; break; }
2902 dd++;
2903 thr->totnum++;
2904 dd += AN0.deferskipped;
2905 if ( AR0.DeferFlag ) {
2906 thr->deferbuffer[defcount++] = AR0.DefPosition;
2907 t1 = AR0.CompressBuffer; j = *t1;
2908 while ( thr->compressbuffer+thr->compressbuffersize-ttco <= j ) {
2909 // the compressbuffer is not large enough!
2910 const ptrdiff_t oldoffset = ttco - thr->compressbuffer;
2911 WORD *top = thr->compressbuffer+thr->compressbuffersize;
2912 DoubleBuffer((void**)&(thr->compressbuffer),(void**)&(top),
2913 sizeof(*(thr->compressbuffer)), "double compressbuffer");
2914 ttco = thr->compressbuffer + oldoffset;
2915 thr->compressbuffersize *= 2;
2916 }
2917 NCOPY(ttco,t1,j);
2918 }
2919 if ( AC.CollectFun && *tt < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
2920 if ( ( ddd = GetMoreTerms(tt) ) < 0 ) {
2921 LowerSortLevel(); goto ProcErr;
2922 }
2923 dd += ddd;
2924 }
2925 t1 = tt;
2926 tt += *tt;
2927 }
2928/*
2929 Check whether there are regular brackets and if we have no DeferFlag
2930 and no collect, we try to add more terms till we finish the current
2931 bracket. We should however not overdo it. Let us say: up to 20%
2932 more terms are allowed.
2933*/
2934 if ( bra ) {
2935 tstop = t1 + *t1; tstop -= ABS(tstop[-1]);
2936 t2 = t1+1;
2937 while ( t2 < tstop ) {
2938 if ( t2[0] == HAAKJE ) { break; }
2939 t2 += t2[1];
2940 }
2941 if ( t2[0] == HAAKJE ) {
2942 t2 += t2[1]; num = t2 - t1;
2943 while ( ( dd < thrbufsiz2 ) &&
2944 ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer - 2 ) ) {
2945/*
2946 First check:
2947*/
2948 if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
2949/*
2950 There is room in the bucket. Fill yet another term.
2951*/
2952 if ( ( fromspectator
2953 ? GetFromSpectator(tt,fromspectator-1)
2954 : GetTermP(B0,tt) ) == 0 ) { endofinput = 1; break; }
2955/*
2956 Same bracket?
2957*/
2958 tstop = tt + *tt; tstop -= ABS(tstop[-1]);
2959 if ( tstop-tt < num ) { /* Different: abort */
2960 AR0.KeptInHold = 1;
2961 break;
2962 }
2963 for ( i = 1; i < num; i++ ) {
2964 if ( t1[i] != tt[i] ) break;
2965 }
2966 if ( i < num ) { /* Different: abort */
2967 AR0.KeptInHold = 1;
2968 break;
2969 }
2970/*
2971 Same bracket. We need this term.
2972*/
2973 dd++;
2974 thr->totnum++;
2975 tt += *tt;
2976 }
2977 }
2978 }
2979 thr->ddterms = dd; /* total number of terms including keep brackets */
2980 thr->firstterm = AN0.ninterms;
2981 AN0.ninterms += dd;
2982 *tt = 0; /* mark end of bucket */
2983 thr->free = BUCKETFILLED;
2984 thr->type = BUCKETDOINGTERMS;
2985 numberoffullbuckets++;
2986 if ( topofavailables <= 0 && endofinput == 0 ) {
2987/*
2988 Problem: topofavailables may already be > 0, but the
2989 thread has not yet gone into waiting. Can the signal get lost?
2990 How can we tell that a thread is waiting for a signal?
2991
2992 All threads are busy. Try to load up another bucket.
2993 In the future we could be more sophisticated.
2994 At the moment we load a complete bucket which could be
2995 1000 terms or even more.
2996 In principle it is better to keep a full bucket ready
2997 and check after each term we put in the next bucket. That
2998 way we don't waste time of the workers.
2999*/
3000 for ( j = 0; j < numthreadbuckets; j++ ) {
3001 switch ( threadbuckets[j]->free ) {
3002 case BUCKETFREE:
3003 thr = threadbuckets[j];
3004 if ( !endofinput ) goto NextBucket;
3005/*
3006 If we are at the end of the input we mark
3007 the free buckets in a special way. That way
3008 we don't keep running into them.
3009*/
3010 thr->free = BUCKETATEND;
3011 break;
3012 case BUCKETCOMINGFREE:
3013 thr = threadbuckets[j];
3014 thr->free = BUCKETFREE;
3015/*
3016 Bucket has just been finished.
3017 Put at the end of the list. We don't want
3018 an early bucket to wait to be treated last.
3019*/
3020 for ( k = j+1; k < numthreadbuckets; k++ )
3021 threadbuckets[k-1] = threadbuckets[k];
3022 threadbuckets[numthreadbuckets-1] = thr;
3023 j--; /* we have to redo the same number j. */
3024 break;
3025 default:
3026 break;
3027 }
3028 }
3029/*
3030 We have no free bucket or we are at the end.
3031 The only thing we can do now is wait for a worker to come free,
3032 provided there are still buckets to send.
3033*/
3034 }
3035/*
3036 Look for the next bucket to send. There is at least one full bucket!
3037*/
3038 for ( j = 0; j < numthreadbuckets; j++ ) {
3039 if ( threadbuckets[j]->free == BUCKETFILLED ) {
3040 thr = threadbuckets[j];
3041 for ( k = j+1; k < numthreadbuckets; k++ )
3042 threadbuckets[k-1] = threadbuckets[k];
3043 threadbuckets[numthreadbuckets-1] = thr;
3044 break;
3045 }
3046 }
3047/*
3048 Wait for a thread to become available
3049 The bucket we are going to use is in thr.
3050*/
3051DoBucket:;
3052 AN0.ninterms++;
3053 while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
3054/*
3055 Prepare the thread. Give it the term and variables.
3056*/
3057 LoadOneThread(0,id,thr,0);
3058 LOCK(thr->lock);
3059 thr->busy = BUCKETASSIGNED;
3060 UNLOCK(thr->lock);
3061 thr->free = BUCKETINUSE;
3062 numberoffullbuckets--;
3063/*
3064 And signal the thread to run.
3065 Form now on we may only interfere with this bucket
3066 1: after it has been marked BUCKETCOMINGFREE
3067 2: when thr->busy == BUCKETDOINGTERM and then only when protected by
3068 thr->lock. This would be for load balancing.
3069*/
3070 WakeupThread(id,LOWESTLEVELGENERATION);
3071/* AN0.ninterms += thr->ddterms; */
3072/*
3073 Now look whether there is another bucket filled and a worker available
3074*/
3075 if ( topofavailables > 0 ) { /* there is a worker */
3076 for ( j = 0; j < numthreadbuckets; j++ ) {
3077 if ( threadbuckets[j]->free == BUCKETFILLED ) {
3078 thr = threadbuckets[j];
3079 for ( k = j+1; k < numthreadbuckets; k++ )
3080 threadbuckets[k-1] = threadbuckets[k];
3081 threadbuckets[numthreadbuckets-1] = thr;
3082 goto DoBucket; /* and we found a bucket */
3083 }
3084 }
3085/*
3086 no bucket is loaded but there is a thread available
3087 find a bucket to load. If there is none (all are USED or ATEND)
3088 we jump out of the loop.
3089*/
3090 for ( j = 0; j < numthreadbuckets; j++ ) {
3091 switch ( threadbuckets[j]->free ) {
3092 case BUCKETFREE:
3093 thr = threadbuckets[j];
3094 if ( !endofinput ) goto NextBucket;
3095 thr->free = BUCKETATEND;
3096 break;
3097 case BUCKETCOMINGFREE:
3098 thr = threadbuckets[j];
3099 if ( endofinput ) {
3100 thr->free = BUCKETATEND;
3101 }
3102 else {
3103 thr->free = BUCKETFREE;
3104 for ( k = j+1; k < numthreadbuckets; k++ )
3105 threadbuckets[k-1] = threadbuckets[k];
3106 threadbuckets[numthreadbuckets-1] = thr;
3107 j--;
3108 }
3109 break;
3110 default:
3111 break;
3112 }
3113 }
3114 if ( j >= numthreadbuckets ) break;
3115 }
3116 else {
3117/*
3118 No worker available.
3119 Look for a bucket to load.
3120 Its number will be in "still"
3121*/
3122Finalize:;
3123 still = -1;
3124 for ( j = 0; j < numthreadbuckets; j++ ) {
3125 switch ( threadbuckets[j]->free ) {
3126 case BUCKETFREE:
3127 thr = threadbuckets[j];
3128 if ( !endofinput ) goto NextBucket;
3129 thr->free = BUCKETATEND;
3130 break;
3131 case BUCKETCOMINGFREE:
3132 thr = threadbuckets[j];
3133 if ( endofinput ) thr->free = BUCKETATEND;
3134 else {
3135 thr->free = BUCKETFREE;
3136 for ( k = j+1; k < numthreadbuckets; k++ )
3137 threadbuckets[k-1] = threadbuckets[k];
3138 threadbuckets[numthreadbuckets-1] = thr;
3139 j--;
3140 }
3141 break;
3142 case BUCKETFILLED:
3143 if ( still < 0 ) still = j;
3144 break;
3145 default:
3146 break;
3147 }
3148 }
3149 if ( still < 0 ) {
3150/*
3151 No buckets to be executed and no buckets FREE.
3152 We must be at the end. Break out of the loop.
3153*/
3154 break;
3155 }
3156 thr = threadbuckets[still];
3157 for ( k = still+1; k < numthreadbuckets; k++ )
3158 threadbuckets[k-1] = threadbuckets[k];
3159 threadbuckets[numthreadbuckets-1] = thr;
3160 goto DoBucket;
3161 }
3162NextBucket:;
3163 }
3164/*
3165 Now the stage one load balancing.
3166 If the load has been readjusted we have again filled buckets.
3167 In that case we jump back in the loop.
3168
3169 Tricky point: when do the workers see the new value of AT.LoadBalancing?
3170 It should activate the locks on thr->busy
3171*/
3172 if ( AC.ThreadBalancing ) {
3173 for ( id = 1; id <= numberofworkers; id++ ) {
3174 AB[id]->T.LoadBalancing = 1;
3175 }
3176 if ( LoadReadjusted() ) goto Finalize;
3177 for ( id = 1; id <= numberofworkers; id++ ) {
3178 AB[id]->T.LoadBalancing = 0;
3179 }
3180 }
3181 if ( AC.ThreadBalancing ) {
3182/*
3183 The AS.Balancing flag should have Generator look for
3184 free workers and apply the "buro" method.
3185
3186 There is still a serious problem.
3187 When for instance a sum_, there may be space created in a local
3188 compiler buffer for a wildcard substitution or whatever.
3189 Compiler buffer execution scribble space.....
3190 This isn't copied along?
3191 Look up ebufnum. There are 12 places with AddRHS!
3192 Problem: one process allocates in ebuf. Then term is given to
3193 other process. It would like to use from this ebuf, but the sender
3194 finishes first and removes the ebuf (and/or overwrites it).
3195
3196 Other problem: local $ variables aren't copied along.
3197*/
3198 AS.Balancing = 0;
3199 }
3200 MasterWaitAll();
3201 AS.Balancing = 0;
3202/*
3203 When we deal with the last expression we can now remove the input
3204 scratch file. This saves potentially much disk space (up to 1/3)
3205*/
3206 if ( LastExpression ) {
3207 UpdateMaxSize();
3208 if ( AR0.infile->handle >= 0 ) {
3209 CloseFile(AR0.infile->handle);
3210 AR0.infile->handle = -1;
3211 remove(AR0.infile->name);
3212 PUTZERO(AR0.infile->POposition);
3213 AR0.infile->POfill = AR0.infile->POfull = AR0.infile->PObuffer;
3214 }
3215 }
3216/*
3217 We order the threads to finish in the SortBotMasterMerge routine
3218 It will start with waiting for all threads to finish.
3219 One could make an administration in which threads that have
3220 finished can start already with the final sort but
3221 1: The load balancing should not make this super urgent
3222 2: It would definitely not be very compatible with the second
3223 stage load balancing.
3224*/
3225 oldgzipCompress = AR0.gzipCompress;
3226 AR0.gzipCompress = 0;
3227 if ( AR0.outtohide ) AR0.outfile = AR0.hidefile;
3228 if ( SortBotMasterMerge() < 0 ) {
3229 if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3230 AR0.gzipCompress = oldgzipCompress;
3231 goto ProcErr;
3232 }
3233 if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3234 AR0.gzipCompress = oldgzipCompress;
3235/*
3236 Now wait for all threads to be ready to give them the cleaning up signal.
3237 With the new SortBotMasterMerge routine we can do the cleanup already automatically
3238 avoiding having to send these signals.
3239*/
3240 MasterWaitAll();
3241 AR0.sLevel--;
3242 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
3243 if ( GetThread(id) > 0 ) WakeupThread(id,CLEANUPEXPRESSION);
3244 }
3245 e->numdummies = 0;
3246 for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
3247 if ( AB[id]->R.MaxDum - AM.IndDum > e->numdummies )
3248 e->numdummies = AB[id]->R.MaxDum - AM.IndDum;
3249 AR0.expchanged |= AB[id]->R.expchanged;
3250 }
3251/*
3252 And wait for all to be clean.
3253*/
3254 MasterWaitAll();
3255 AT0.WorkPointer = oldworkpointer;
3256 return(0);
3257ProcErr:;
3258 return(-1);
3259}
3260
3261/*
3262 #] ThreadsProcessor :
3263 #[ LoadReadjusted :
3264*/
3283int LoadReadjusted(void)
3284{
3285 ALLPRIVATES *B0 = AB[0];
3286 THREADBUCKET *thr = 0, *thrtogo = 0;
3287 int numtogo, numfree, numbusy, n, nperbucket, extra, i, j, u, bus;
3288 LONG numinput;
3289 WORD *t1, *c1, *t2, *c2, *t3;
3290/*
3291 Start with waiting for at least one free processor.
3292 We don't want the master competing for time when all are busy.
3293*/
3294 while ( topofavailables <= 0 ) MasterWait();
3295/*
3296 Now look for the fullest bucket and make a list of free buckets
3297 The bad part is that most numbers can change at any moment.
3298*/
3299restart:;
3300 numtogo = 0;
3301 numfree = 0;
3302 numbusy = 0;
3303 for ( j = 0; j < numthreadbuckets; j++ ) {
3304 thr = threadbuckets[j];
3305 if ( thr->free == BUCKETFREE || thr->free == BUCKETATEND
3306 || thr->free == BUCKETCOMINGFREE ) {
3307 freebuckets[numfree++] = thr;
3308 }
3309 else if ( thr->type != BUCKETDOINGTERMS ) {}
3310 else if ( thr->totnum > 1 ) { /* never steal from a bucket with one term */
3311 LOCK(thr->lock);
3312 bus = thr->busy;
3313 UNLOCK(thr->lock);
3314 if ( thr->free == BUCKETINUSE ) {
3315 n = thr->totnum-thr->usenum;
3316 if ( bus == BUCKETASSIGNED ) numbusy++;
3317 else if ( ( bus != BUCKETASSIGNED )
3318 && ( n > numtogo ) ) {
3319 numtogo = n;
3320 thrtogo = thr;
3321 }
3322 }
3323 else if ( bus == BUCKETTOBERELEASED
3324 && thr->free == BUCKETRELEASED ) {
3325 freebuckets[numfree++] = thr;
3326 thr->free = BUCKETATEND;
3327 LOCK(thr->lock);
3328 thr->busy = BUCKETPREPARINGTERM;
3329 UNLOCK(thr->lock);
3330 }
3331 }
3332 }
3333 if ( numfree == 0 ) return(0); /* serious problem */
3334 if ( numtogo > 0 ) { /* provisionally there is something to be stolen */
3335 thr = thrtogo;
3336/*
3337 If the number has changed there is good progress.
3338 Maybe there is another thread that needs assistance.
3339 We start all over.
3340*/
3341 if ( thr->totnum-thr->usenum < numtogo ) goto restart;
3342/*
3343 If the thread is in the term loading phase
3344 (thr->busy == BUCKETPREPARINGTERM) we better stay away from it.
3345 We wait now for the thread to be busy, and don't allow it
3346 now to drop out of this state till we are done here.
3347 This all depends on whether AT.LoadBalancing == 1 is seen by
3348 the thread.
3349*/
3350 LOCK(thr->lock);
3351 if ( thr->busy != BUCKETDOINGTERM ) {
3352 UNLOCK(thr->lock);
3353 goto restart;
3354 }
3355 if ( thr->totnum-thr->usenum < numtogo ) {
3356 UNLOCK(thr->lock);
3357 goto restart;
3358 }
3359 thr->free = BUCKETTERMINATED;
3360/*
3361 The above will signal the thread we want to terminate.
3362 Next all effort goes into making sure the landing is soft.
3363 Unfortunately we don't want to wait for a signal, because the thread
3364 may be working for a long time on a single term.
3365*/
3366 if ( thr->usenum == thr->totnum ) {
3367/*
3368 Terminated in the mean time or by now working on the
3369 last term. Try again.
3370*/
3371 thr->free = BUCKETATEND;
3372 UNLOCK(thr->lock);
3373 goto restart;
3374 }
3375 goto intercepted;
3376 }
3377/* This has always been commented. Indeed no lock is held here. */
3378/* UNLOCK(thr->lock); */
3379 if ( numbusy > 0 ) {
3380 /* JD: this avoids large runtimes for tform tests under valgrind.
3381 What seems to happen is we return from here, goto Finalize, and
3382 end up in LoadReadjusted again without the threads having a
3383 chance to update their busy status. Then we end up here again.
3384 Sleep the thread for, say, 1us to allow threads to aquire the lock. */
3385 struct timespec sleeptime;
3386 sleeptime.tv_sec = 0;
3387 sleeptime.tv_nsec = 1000L;
3388 nanosleep(&sleeptime, NULL);
3389 return(1); /* Wait a bit.... */
3390 }
3391 return(0);
3392intercepted:;
3393/*
3394 We intercepted one successfully. Now it becomes interesting. Action:
3395 1: determine how many terms per free bucket.
3396 2: find the first untreated term.
3397 3: put the terms in the free buckets.
3398
3399 Remember: we still have the lock to avoid interference from the thread
3400 that is being robbed. We were holding it and then jumped here with
3401 goto intercepted.
3402*/
3403 numinput = thr->firstterm + thr->usenum;
3404 nperbucket = numtogo / numfree;
3405 extra = numtogo - nperbucket*numfree;
3406 if ( AR0.DeferFlag ) {
3407 t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
3408 for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
3409 t3 = t1;
3410 if ( extra > 0 ) {
3411 for ( i = 0; i < extra; i++ ) {
3412 thrtogo = freebuckets[i];
3413 t2 = thrtogo->threadbuffer;
3414 c2 = thrtogo->compressbuffer;
3415 thrtogo->free = BUCKETFILLED;
3416 thrtogo->type = BUCKETDOINGTERMS;
3417 thrtogo->totnum = nperbucket+1;
3418 thrtogo->ddterms = 0;
3419 thrtogo->usenum = 0;
3420 thrtogo->busy = BUCKETASSIGNED;
3421 thrtogo->firstterm = numinput;
3422 numinput += nperbucket+1;
3423 for ( n = 0; n <= nperbucket; n++ ) {
3424 j = *t1; NCOPY(t2,t1,j);
3425 j = *c1; NCOPY(c2,c1,j);
3426 thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
3427 }
3428 *t2 = *c2 = 0;
3429 }
3430 }
3431 if ( nperbucket > 0 ) {
3432 for ( i = extra; i < numfree; i++ ) {
3433 thrtogo = freebuckets[i];
3434 t2 = thrtogo->threadbuffer;
3435 c2 = thrtogo->compressbuffer;
3436 thrtogo->free = BUCKETFILLED;
3437 thrtogo->type = BUCKETDOINGTERMS;
3438 thrtogo->totnum = nperbucket;
3439 thrtogo->ddterms = 0;
3440 thrtogo->usenum = 0;
3441 thrtogo->busy = BUCKETASSIGNED;
3442 thrtogo->firstterm = numinput;
3443 numinput += nperbucket;
3444 for ( n = 0; n < nperbucket; n++ ) {
3445 j = *t1; NCOPY(t2,t1,j);
3446 j = *c1; NCOPY(c2,c1,j);
3447 thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
3448 }
3449 *t2 = *c2 = 0;
3450 }
3451 }
3452 }
3453 else {
3454 t1 = thr->threadbuffer;
3455 for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
3456 t3 = t1;
3457 if ( extra > 0 ) {
3458 for ( i = 0; i < extra; i++ ) {
3459 thrtogo = freebuckets[i];
3460 t2 = thrtogo->threadbuffer;
3461 thrtogo->free = BUCKETFILLED;
3462 thrtogo->type = BUCKETDOINGTERMS;
3463 thrtogo->totnum = nperbucket+1;
3464 thrtogo->ddterms = 0;
3465 thrtogo->usenum = 0;
3466 thrtogo->busy = BUCKETASSIGNED;
3467 thrtogo->firstterm = numinput;
3468 numinput += nperbucket+1;
3469 for ( n = 0; n <= nperbucket; n++ ) {
3470 j = *t1; NCOPY(t2,t1,j);
3471 }
3472 *t2 = 0;
3473 }
3474 }
3475 if ( nperbucket > 0 ) {
3476 for ( i = extra; i < numfree; i++ ) {
3477 thrtogo = freebuckets[i];
3478 t2 = thrtogo->threadbuffer;
3479 thrtogo->free = BUCKETFILLED;
3480 thrtogo->type = BUCKETDOINGTERMS;
3481 thrtogo->totnum = nperbucket;
3482 thrtogo->ddterms = 0;
3483 thrtogo->usenum = 0;
3484 thrtogo->busy = BUCKETASSIGNED;
3485 thrtogo->firstterm = numinput;
3486 numinput += nperbucket;
3487 for ( n = 0; n < nperbucket; n++ ) {
3488 j = *t1; NCOPY(t2,t1,j);
3489 }
3490 *t2 = 0;
3491 }
3492 }
3493 }
3494 *t3 = 0; /* This is some form of extra insurance */
3495 if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
3496 thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
3497 }
3498 UNLOCK(thr->lock);
3499 return(1);
3500}
3501
3502/*
3503 #] LoadReadjusted :
3504 #[ SortStrategy :
3505*/
3538/*
3539 #] SortStrategy :
3540 #[ PutToMaster :
3541*/
3560int PutToMaster(PHEAD WORD *term)
3561{
3562 int i,j,nexti,ret = 0;
3563 int urgent = 0;
3564 WORD *t, *fill, *top, zero = 0;
3565 if ( term == 0 ) { /* Mark the end of the expression */
3566 t = &zero; j = 1;
3567 }
3568 else {
3569 t = term; ret = j = *term;
3570 if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
3571 }
3572 i = AT.SB.FillBlock; /* The block we are working at */
3573 fill = AT.SB.MasterFill[i]; /* Where we are filling */
3574 top = AT.SB.MasterStop[i]; /* End of the block */
3575
3576 // If there is space in the block, and we have already written MINWRITENUMBEROFTERMS,
3577 // determine if the reading thread is waiting for us by trying to lock the previous
3578 // block. If we manage to lock it, then we still have time to continue filling this
3579 // block. If we can't lock it, the reading thread is waiting for us and we should
3580 // move to the next block ASAP.
3581 if ( j < top - fill && AT.SB.BlockTerms[i] > MINWRITENUMBEROFTERMS ) {
3582 const int prev = ( i == 1 ? AT.SB.MasterNumBlocks : i-1 );
3583 if ( ! pthread_mutex_trylock(&(AT.SB.MasterBlockLock[prev])) ) {
3584 UNLOCK(AT.SB.MasterBlockLock[prev]);
3585 }
3586 else {
3587 urgent = 1;
3588 }
3589 }
3590
3591 // If the term doesn't fit in the current block, or a thread is waiting for us
3592 // (and we've already written at least MINWRITENUMBEROFTERMS), move to the next:
3593 if ( ( j >= top - fill ) || urgent ) {
3594 nexti = i+1;
3595 if ( nexti > AT.SB.MasterNumBlocks ) {
3596 nexti = 1;
3597 }
3598 LOCK(AT.SB.MasterBlockLock[nexti]);
3599 UNLOCK(AT.SB.MasterBlockLock[i]);
3600 AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
3601 AT.SB.FillBlock = i = nexti;
3602 fill = AT.SB.MasterStart[i];
3603 top = AT.SB.MasterStop[i];
3604 if ( AT.SB.BlockTerms[i] != 0 ) {
3605 // In this case, there has been an accounting error in a previous use
3606 // of this block. Blocks that have been read from and unlocked, should
3607 // have BlockTerms == 0.
3608/* INTERNAL_ERROR_EXCL_START */
3609 MLOCK(ErrorMessageLock);
3610 MesPrint("!>Error in PutToMaster, starting a block with BlockTerms != 0");
3611 MUNLOCK(ErrorMessageLock);
3612 Terminate(-1);
3613/* INTERNAL_ERROR_EXCL_STOP */
3614 }
3615 }
3616
3617 NCOPY(fill, t, j);
3618 AT.SB.BlockTerms[i]++;
3619 AT.SB.MasterFill[i] = fill;
3620 return(ret);
3621}
3622
3623/*
3624 #] PutToMaster :
3625 #[ SortBotOut :
3626*/
3627
3628
3637int
3638SortBotOut(PHEAD WORD *term)
3639{
3640 WORD im;
3641
3642 if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
3643
3644 if ( term == 0 ) {
3645 if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
3646 ADDPOS(AT.SS->SizeInFile[0],1);
3647 return(0);
3648 }
3649 else {
3650 numberofterms++;
3651 if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
3652/* INTERNAL_ERROR_EXCL_START */
3653 MLOCK(ErrorMessageLock);
3654 MesPrint("Called from SortBotMasterMerge/SortBotOut");
3655 MUNLOCK(ErrorMessageLock);
3656 return(-1);
3657/* INTERNAL_ERROR_EXCL_STOP */
3658 }
3659 ADDPOS(AT.SS->SizeInFile[0],im);
3660 return(im);
3661 }
3662}
3663
3664/*
3665 #] SortBotOut :
3666 #[ SortBotMasterMerge :
3667*/
3668
3669
3685int SortBotMasterMerge(void)
3686{
3687 FILEHANDLE *fin, *fout;
3688 ALLPRIVATES *B = AB[0], *BB;
3689 POSITION position;
3690 SORTING *S = AT.SS;
3691 int i, j;
3692/*
3693 Get the sortbots get to claim their writing blocks.
3694 We have to wait till all have been claimed because they also have to
3695 claim the last writing blocks of the workers to prevent the head of
3696 the circular buffer to overrun the tail.
3697
3698 Before waiting we can do some needed initializations.
3699 Also the master has to claim the last writing blocks of its input.
3700*/
3701 topsortbotavailables = 0;
3702 for ( i = numberofworkers+1; i <= numberofworkers+GetNumberOfSortBots(numberofworkers); i++ ) {
3703 WakeupThread(i,INISORTBOT);
3704 }
3705
3706 AS.MasterSort = 1;
3707 fout = AR.outfile;
3708 numberofterms = 0;
3709 AR.CompressPointer[0] = 0;
3710 numberclaimed = 0;
3711 BB = AB[AT.SortBotIn1];
3712 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
3713 if ( AT.SortBotIn2 >= 0 ) {
3714 BB = AB[AT.SortBotIn2];
3715 LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
3716 }
3717
3718 MasterWaitAllSortBots();
3719/*
3720 Now we can start up the workers. They will claim their writing blocks.
3721 Here the master will wait till all writing blocks have been claimed.
3722*/
3723 for ( i = 1; i <= numberofworkers; i++ ) {
3724 j = GetThread(i);
3725 WakeupThread(i,FINISHEXPRESSION);
3726 }
3727/*
3728 Prepare the output file in the mean time.
3729*/
3730 if ( fout->handle >= 0 ) {
3731 PUTZERO(SortBotPosition);
3732 SeekFile(fout->handle,&SortBotPosition,SEEK_END);
3733 ADDPOS(SortBotPosition,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
3734 }
3735 else {
3736 SETBASEPOSITION(SortBotPosition,(fout->POfill-fout->PObuffer)*sizeof(WORD));
3737 }
3738 MasterWaitAllBlocks();
3739/*
3740 Now we can start the sortbots after which the master goes in
3741 sortbot mode to do its part of the job (the very final merge and
3742 the writing to output file).
3743*/
3744 topsortbotavailables = 0;
3745 for ( i = numberofworkers+1; i <= numberofworkers+GetNumberOfSortBots(numberofworkers); i++ ) {
3746 WakeupThread(i,RUNSORTBOT);
3747 }
3748 if ( SortBotMerge(BHEAD0) ) {
3749/* INTERNAL_ERROR_EXCL_START */
3750 MLOCK(ErrorMessageLock);
3751 MesPrint("!>Called from SortBotMasterMerge");
3752 MUNLOCK(ErrorMessageLock);
3753 AS.MasterSort = 0;
3754 return(-1);
3755/* INTERNAL_ERROR_EXCL_STOP */
3756 }
3757/*
3758 And next the cleanup
3759*/
3760 if ( S->file.handle >= 0 )
3761 {
3762 fin = &S->file;
3763 CloseFile(fin->handle);
3764 remove(fin->name);
3765 fin->handle = -1;
3766 }
3767 position = S->SizeInFile[0];
3768 MULPOS(position,sizeof(WORD));
3769
3770 // Collect global sort statistics information from the threads.
3771 // The total GenTerms is the sum of the thread GenTerms.
3772 // The total small/large buffer sort info is the sum of the thread info.
3773 // The total comparison count is the sum of the thread and sortbot counts.
3774 // The total unsorted size is the sum of the total generated terms sizes
3775 // The total maximal term size is the maximum of all maximal term sizes
3776 S->GenTerms = 0;
3777 for ( j = 1; j <= numberofworkers; j++ ) {
3778 S->GenTerms += AB[j]->T.SS->GenTerms;
3779 S->verbComparisons += AB[j]->T.SS->verbComparisons;
3780 if ( S->verbMaxTermSize < AB[j]->T.SS->verbMaxTermSize )
3781 S->verbMaxTermSize = AB[j]->T.SS->verbMaxTermSize;
3782 S->verbSBsortTerms += AB[j]->T.SS->verbSBsortTerms;
3783 S->verbSBsortCap += AB[j]->T.SS->verbSBsortCap;
3784 S->verbLBsortPatches += AB[j]->T.SS->verbLBsortPatches;
3785 S->verbLBsortCap += AB[j]->T.SS->verbLBsortCap;
3786 S->verbUnsortedSize += AB[j]->T.SS->verbUnsortedSize;
3787 }
3788 for ( j = numberofworkers+1; j <= numberofworkers+GetNumberOfSortBots(numberofworkers); j++ ) {
3789 S->verbComparisons += AB[j]->T.SS->verbComparisons;
3790 if ( S->verbMaxTermSize < AB[j]->T.SS->verbMaxTermSize )
3791 S->verbMaxTermSize = AB[j]->T.SS->verbMaxTermSize;
3792 }
3793
3794 S->TermsLeft = numberofterms;
3795 WriteStats(&position,STATSPOSTSORT,NOCHECKLOGTYPE);
3796 Expressions[AR.CurExpr].counter = S->TermsLeft;
3797 Expressions[AR.CurExpr].size = position;
3798 AS.MasterSort = 0;
3799/*
3800 The next statement is to prevent one of the sortbots not having
3801 completely cleaned up before the next module starts.
3802 If this statement is omitted every once in a while one of the sortbots
3803 is still running when the next expression starts and misses its
3804 initialization. The result is usually disastrous.
3805*/
3806 MasterWaitAllSortBots();
3807
3808 return(0);
3809}
3810
3811
3812/*
3813 #] SortBotMasterMerge :
3814 #[ SortBotMerge :
3815*/
3816
3817
3823int SortBotMerge(PHEAD0)
3824{
3825 GETBIDENTITY
3826 ALLPRIVATES *Bin1, *Bin2;
3827 Bin1 = AB[AT.SortBotIn1];
3828 if ( AT.SortBotIn2 >= 0 ) {
3829 Bin2 = AB[AT.SortBotIn2];
3830 }
3831 else {
3832 // Incorrect dereference of this will cause a crash: all accesses must
3833 // be protected with with "if ( AT.SortBotIn2 >= 0 )"
3834 Bin2 = NULL;
3835 }
3836 WORD *term1, *term2, *wp;
3837 int blin1, blin2; /* Current block numbers */
3838 int error = 0;
3839 WORD l1, l2, *m1, *m2, *w, r1, r2, r3, r33, r31, *tt1, ii;
3840 WORD *to, *from, im, c;
3841 UWORD *coef;
3842 SORTING *S = AT.SS;
3843#ifdef WITHFLOAT
3844 WORD *fun1, *fun2, *fun3, *tstop1, *tstop2, size1, size2, size3, l3, jj, *m3;
3845#endif
3846/*
3847 Set the pointers to the input terms and the output space
3848*/
3849 coef = AN.SoScratC;
3850 blin1 = 1;
3851 blin2 = 1;
3852 if ( AT.identity == 0 ) {
3853 wp = AT.WorkPointer;
3854 }
3855 else {
3856 wp = AT.WorkPointer = AT.WorkSpace;
3857 }
3858/*
3859 Get the locks for reading the input
3860 This means that we can start once these locks have been cleared
3861 which means that there will be input.
3862*/
3863 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
3864 if ( AT.SortBotIn2 >= 0 ) {
3865 LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
3866 }
3867 term1 = Bin1->T.SB.MasterStart[blin1];
3868 WORD zeroterm = 0;
3869 term2 = &zeroterm;
3870 if ( AT.SortBotIn2 >= 0 ) {
3871 term2 = Bin2->T.SB.MasterStart[blin2];
3872 }
3873 AT.SB.FillBlock = 1;
3874/*
3875 Now the main loop. Keep going until one of the two hits the end.
3876*/
3877 while ( *term1 && *term2 ) {
3878 if ( ( c = CompareTerms(BHEAD term1,term2,(WORD)0) ) > 0 ) {
3879/*
3880 #[ One is smallest :
3881*/
3882 Bin1->T.SB.BlockTerms[blin1]--;
3883 if ( SortBotOut(BHEAD term1) < 0 ) {
3884/* INTERNAL_ERROR_EXCL_START */
3885 MLOCK(ErrorMessageLock);
3886 MesPrint("!>Called from SortBotMerge with thread = %d",AT.identity);
3887 MUNLOCK(ErrorMessageLock);
3888 error = -1;
3889 goto ReturnError;
3890/* INTERNAL_ERROR_EXCL_STOP */
3891 }
3892 term1 += *term1;
3893 if ( Bin1->T.SB.BlockTerms[blin1] == 0 ) {
3894 if ( blin1 == 1 ) {
3895 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
3896 }
3897 else {
3898 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
3899 }
3900 if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
3901 blin1 = 1;
3902 }
3903 else {
3904 blin1++;
3905 }
3906 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
3907 Bin1->T.SB.MasterBlock = blin1;
3908 term1 = Bin1->T.SB.MasterStart[blin1];
3909 }
3910/*
3911 #] One is smallest :
3912*/
3913 }
3914 else if ( c < 0 ) {
3915/*
3916 #[ Two is smallest :
3917*/
3918 Bin2->T.SB.BlockTerms[blin2]--;
3919 if ( SortBotOut(BHEAD term2) < 0 ) {
3920/* INTERNAL_ERROR_EXCL_START */
3921 MLOCK(ErrorMessageLock);
3922 MesPrint("!>Called from SortBotMerge with thread = %d",AT.identity);
3923 MUNLOCK(ErrorMessageLock);
3924 error = -1;
3925 goto ReturnError;
3926/* INTERNAL_ERROR_EXCL_STOP */
3927 }
3928next2:
3929 term2 += *term2;
3930 if ( Bin2->T.SB.BlockTerms[blin2] == 0 ) {
3931 if ( blin2 == 1 ) {
3932 UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
3933 }
3934 else {
3935 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
3936 }
3937 if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
3938 blin2 = 1;
3939 }
3940 else {
3941 blin2++;
3942 }
3943 LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
3944 Bin2->T.SB.MasterBlock = blin2;
3945 term2 = Bin2->T.SB.MasterStart[blin2];
3946 }
3947/*
3948 #] Two is smallest :
3949*/
3950 }
3951 else {
3952/*
3953 #[ Equal :
3954*/
3955 Bin1->T.SB.BlockTerms[blin1]--;
3956 Bin2->T.SB.BlockTerms[blin2]--;
3957 l1 = *( m1 = term1 );
3958 l2 = *( m2 = term2 );
3959 if ( S->PolyWise ) { /* Here we work with PolyFun */
3960 tt1 = m1;
3961 m1 += S->PolyWise;
3962 m2 += S->PolyWise;
3963 if ( S->PolyFlag == 2 ) {
3964 AT.WorkPointer = wp;
3965 w = poly_ratfun_add(BHEAD m1,m2);
3966 if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
3967 MLOCK(ErrorMessageLock);
3968 MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
3969 MUNLOCK(ErrorMessageLock);
3970 Terminate(-1);
3971 }
3972 AT.WorkPointer = wp;
3973 if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
3974 goto cancelled;
3975 }
3976 }
3977 else {
3978 w = wp;
3979 if ( w + m1[1] + m2[1] > AT.WorkTop ) {
3980 MLOCK(ErrorMessageLock);
3981 MesPrint("SortBotMerge(%d): A Maxtermsize of %10l is too small",
3982 AT.identity,AM.MaxTer/sizeof(WORD));
3983 MesPrint("m1[1] = %d, m2[1] = %d, Space = %l",m1[1],m2[1],(LONG)(AT.WorkTop-wp));
3984 PrintTerm(term1,"term1");
3985 PrintTerm(term2,"term2");
3986 MesPrint("PolyWise = %d",S->PolyWise);
3987 MUNLOCK(ErrorMessageLock);
3988 Terminate(-1);
3989 }
3990 AddArgs(BHEAD m1,m2,w);
3991 }
3992 r1 = w[1];
3993 if ( r1 <= FUNHEAD
3994 || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
3995 { goto cancelled; }
3996 if ( r1 == m1[1] ) {
3997 NCOPY(m1,w,r1);
3998 }
3999 else if ( r1 < m1[1] ) {
4000 r2 = m1[1] - r1;
4001 m2 = w + r1;
4002 m1 += m1[1];
4003 while ( --r1 >= 0 ) *--m1 = *--m2;
4004 m2 = m1 - r2;
4005 r1 = S->PolyWise;
4006 while ( --r1 >= 0 ) *--m1 = *--m2;
4007 *m1 -= r2;
4008 term1 = m1;
4009 }
4010 else {
4011 // Here we are writing the new merged term *before* the original start of term1.
4012 // We can always do this, since before term1 there is previous term data of this
4013 // block, or the previous block, for which we are holding a lock. This requires
4014 // the existence of "block 0", if term1 is the first term of block 1!
4015 // It also requires the blocks to be contiguous in memory; we can't allocate
4016 // separate memory regions for each block without larger-scale changes.
4017 r2 = r1 - m1[1];
4018 m2 = tt1 - r2;
4019 r1 = S->PolyWise;
4020 m1 = tt1;
4021 *m1 += r2;
4022 term1 = m2;
4023 NCOPY(m2,m1,r1);
4024 r1 = w[1];
4025 NCOPY(m2,w,r1);
4026 }
4027 }
4028#ifdef WITHFLOAT
4029 else if ( AT.SortFloatMode ) {
4030/*
4031 The terms are in m1/term1 and m2/term2 and their length in l1 and l2.
4032 We have to locate the floats which have already been
4033 verified in the compare routine. Once we have the new
4034 term we can jump to the code that writes away the
4035 result after adding the rationals.
4036*/
4037 tstop1 = m1+l1; size1 = tstop1[-1]; tstop1 -= ABS(size1);
4038 tstop2 = m2+l2; size2 = tstop2[-1]; tstop2 -= ABS(size2);
4039 if ( AT.SortFloatMode == 3 ) {
4040 fun1 = m1+1;
4041 while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
4042 fun1 += fun1[1];
4043 }
4044 if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
4045 UnpackFloat(aux1,fun1);
4046 fun2 = m2+1;
4047 while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
4048 fun2 += fun2[1];
4049 }
4050 if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
4051 UnpackFloat(aux2,fun2);
4052 }
4053 else if ( AT.SortFloatMode == 1 ) {
4054 fun1 = m1+1;
4055 while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
4056 fun1 += fun1[1];
4057 }
4058 if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
4059 UnpackFloat(aux1,fun1);
4060 fun2 = tstop2;
4061 RatToFloat(aux2,(UWORD *)fun2,size2);
4062 }
4063 else if ( AT.SortFloatMode == 2 ) {
4064 fun1 = tstop1;
4065 RatToFloat(aux1,(UWORD *)fun1,size1);
4066 fun2 = m2+1;
4067 while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
4068 fun2 += fun2[1];
4069 }
4070 if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
4071 UnpackFloat(aux2,fun2);
4072 }
4073 else {
4074/* INTERNAL_ERROR_EXCL_START */
4075 MLOCK(ErrorMessageLock);
4076 MesPrint("!>Illegal value %d for AT.SortFloatMode in SortBotMerge.",AT.SortFloatMode);
4077 MUNLOCK(ErrorMessageLock);
4078 Terminate(-1);
4079 return(0);
4080/* INTERNAL_ERROR_EXCL_STOP */
4081 }
4082 mpf_add(aux3,aux1,aux2);
4083 size3 = mpf_sgn(aux3);
4084 if ( size3 == 0 ) { /* Cancelling! Rare! */
4085 goto cancelled;
4086 }
4087 else if ( size3 < 0 ) mpf_neg(aux3,aux3);
4088 fun3 = TermMalloc("SortBotMasterMerge");
4089 PackFloat(fun3,aux3);
4090 l3 = fun3[1]+(fun1-m1)+3; /* new size */
4091
4092 if ( l3 != l1 ) {
4093/*
4094 Copy it all to wp
4095*/
4096 if ( (l3)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
4097 MLOCK(ErrorMessageLock);
4098 MesPrint("SortBotMasterMerge: Coefficient overflow during sort");
4099 MUNLOCK(ErrorMessageLock);
4100 goto ReturnError;
4101 }
4102 m3 = wp; m2 = term1;
4103 while ( m2 < fun1 ) *m3++ = *m2++;
4104 for ( jj = 0; jj < fun3[1]; jj++ ) *m3++ = fun3[jj];
4105 *m3++ = 1; *m3++ = 1;
4106 *m3++ = size3 < 0 ? -3: 3;
4107 *wp = m3-wp;
4108 TermFree(fun3,"SortBotMasterMerge");
4109 goto PutOutwp;
4110 }
4111 for ( jj = 0; jj < fun3[1]; jj++ ) fun1[jj] = fun3[jj];
4112 fun1 += fun3[1];
4113 *fun1++ = 1; *fun1++ = 1;
4114 *fun1++ = size3 < 0 ? -3: 3;
4115 *term1 = fun1-term1;
4116 TermFree(fun3,"SortBotMasterMerge");
4117 }
4118#endif
4119 else {
4120 r1 = *( m1 += l1 - 1 );
4121 m1 -= ABS(r1) - 1;
4122 r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
4123 r2 = *( m2 += l2 - 1 );
4124 m2 -= ABS(r2) - 1;
4125 r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
4126
4127 if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
4128 MLOCK(ErrorMessageLock);
4129 MesCall("SortBotMerge");
4130 MUNLOCK(ErrorMessageLock);
4131 SETERROR(-1)
4132 }
4133
4134 if ( AN.ncmod != 0 ) {
4135 if ( ( AC.modmode & POSNEG ) != 0 ) {
4136 NormalModulus(coef,&r3);
4137 }
4138 else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
4139 SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
4140 coef[r3] = 1;
4141 for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
4142 }
4143 }
4144 if ( !r3 ) { goto cancelled; }
4145 r3 *= 2;
4146 r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
4147 if ( r3 < 0 ) r3 = -r3;
4148 if ( r1 < 0 ) r1 = -r1;
4149 r1 *= 2;
4150 r31 = r3 - r1;
4151 if ( !r31 ) { /* copy coef into term1 */
4152 m2 = (WORD *)coef; im = r3;
4153 NCOPY(m1,m2,im);
4154 *m1 = r33;
4155 }
4156 else {
4157 to = wp; from = term1;
4158 while ( from < m1 ) *to++ = *from++;
4159 from = (WORD *)coef; im = r3;
4160 NCOPY(to,from,im);
4161 *to++ = r33;
4162 wp[0] = to - wp;
4163PutOutwp:
4164 if ( SortBotOut(BHEAD wp) < 0 ) {
4165/* INTERNAL_ERROR_EXCL_START */
4166 MLOCK(ErrorMessageLock);
4167 MesPrint("!>Called from SortBotMerge with thread = %d",AT.identity);
4168 MUNLOCK(ErrorMessageLock);
4169 error = -1;
4170 goto ReturnError;
4171/* INTERNAL_ERROR_EXCL_STOP */
4172 }
4173 goto cancelled;
4174 }
4175 }
4176 if ( SortBotOut(BHEAD term1) < 0 ) {
4177/* INTERNAL_ERROR_EXCL_START */
4178 MLOCK(ErrorMessageLock);
4179 MesPrint("!>Called from SortBotMerge with thread = %d",AT.identity);
4180 MUNLOCK(ErrorMessageLock);
4181 error = -1;
4182 goto ReturnError;
4183/* INTERNAL_ERROR_EXCL_STOP */
4184 }
4185cancelled:; /* Now we need two new terms */
4186 term1 += *term1;
4187 if ( Bin1->T.SB.BlockTerms[blin1] == 0 ) {
4188
4189 if ( blin1 == 1 ) {
4190 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4191 }
4192 else {
4193 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4194 }
4195 if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4196 blin1 = 1;
4197 }
4198 else {
4199 blin1++;
4200 }
4201 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4202 Bin1->T.SB.MasterBlock = blin1;
4203 term1 = Bin1->T.SB.MasterStart[blin1];
4204 }
4205 goto next2;
4206/*
4207 #] Equal :
4208*/
4209 }
4210 }
4211/*
4212 Copy the tail
4213*/
4214 if ( *term1 ) {
4215/*
4216 #[ Tail in one :
4217*/
4218 while ( *term1 ) {
4219 Bin1->T.SB.BlockTerms[blin1]--;
4220 if ( SortBotOut(BHEAD term1) < 0 ) {
4221/* INTERNAL_ERROR_EXCL_START */
4222 MLOCK(ErrorMessageLock);
4223 MesPrint("!>Called from SortBotMerge with thread = %d",AT.identity);
4224 MUNLOCK(ErrorMessageLock);
4225 error = -1;
4226 goto ReturnError;
4227/* INTERNAL_ERROR_EXCL_STOP */
4228 }
4229 if ( Bin1->T.SB.BlockTerms[blin1] == 0 ) {
4230
4231 if ( blin1 == 1 ) {
4232 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4233 }
4234 else {
4235 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4236 }
4237 if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4238 blin1 = 1;
4239 }
4240 else {
4241 blin1++;
4242 }
4243 LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4244 Bin1->T.SB.MasterBlock = blin1;
4245 term1 = Bin1->T.SB.MasterStart[blin1];
4246 }
4247 else {
4248 term1 += *term1;
4249 }
4250 }
4251/*
4252 #] Tail in one :
4253*/
4254 }
4255 else if ( *term2 ) {
4256/*
4257 #[ Tail in two :
4258*/
4259 while ( *term2 ) {
4260 Bin2->T.SB.BlockTerms[blin2]--;
4261 if ( SortBotOut(BHEAD term2) < 0 ) {
4262/* INTERNAL_ERROR_EXCL_START */
4263 MLOCK(ErrorMessageLock);
4264 MesPrint("!>Called from SortBotMerge with thread = %d",AT.identity);
4265 MUNLOCK(ErrorMessageLock);
4266 error = -1;
4267 goto ReturnError;
4268/* INTERNAL_ERROR_EXCL_STOP */
4269 }
4270 if ( Bin2->T.SB.BlockTerms[blin2] == 0 ) {
4271
4272 if ( blin2 == 1 ) {
4273 UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4274 }
4275 else {
4276 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4277 }
4278 if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4279 blin2 = 1;
4280 }
4281 else {
4282 blin2++;
4283 }
4284 LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4285 Bin2->T.SB.MasterBlock = blin2;
4286 term2 = Bin2->T.SB.MasterStart[blin2];
4287 }
4288 else {
4289 term2 += *term2;
4290 }
4291 }
4292/*
4293 #] Tail in two :
4294*/
4295 }
4296
4297 // Both streams have hit the end-of-stream marker "0". We still need to
4298 // decrement the BlockTerms counters a final time, the marker is included
4299 // in the count.
4300 Bin1->T.SB.BlockTerms[blin1]--;
4301 if ( AT.SortBotIn2 >= 0 ) {
4302 Bin2->T.SB.BlockTerms[blin2]--;
4303 }
4304
4305 SortBotOut(BHEAD 0);
4306ReturnError:;
4307/*
4308 Release all locks.
4309*/
4310 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4311 if ( blin1 > 1 ) {
4312 UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
4313 }
4314 else {
4315 UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
4316 }
4317 if ( AT.SortBotIn2 >= 0 ) {
4318 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4319 if ( blin2 > 1 ) {
4320 UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
4321 }
4322 else {
4323 UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
4324 }
4325 }
4326 if ( AT.identity > 0 ) {
4327 UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
4328 }
4329/*
4330 And that was all folks
4331*/
4332 return(error);
4333}
4334
4335
4336/*
4337 #] SortBotMerge :
4338 #[ IniSortBlocks :
4339*/
4340
4341static int SortBlocksInitialized = 0;
4342
4349int IniSortBlocks(int numworkers)
4350{
4351 ALLPRIVATES *B;
4352 SORTING *S;
4353 LONG totalsize, workersize, blocksize, numberofterms;
4354 int maxter, id, j;
4355 int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
4356 WORD *w;
4357
4358 if ( SortBlocksInitialized ) return(0);
4359 SortBlocksInitialized = 1;
4360 if ( numworkers == 0 ) return(0);
4361
4362 if ( GetNumberOfSortBots(numworkers) > 0 ) {
4363 numparts = numworkers + GetNumberOfSortBots(numberofworkers);
4364 numberofblocks = numberofblocks/2;
4365 }
4366 else {
4367 numparts = numworkers;
4368 }
4369 S = AM.S0;
4370 totalsize = S->LargeSize + S->SmallEsize;
4371 workersize = totalsize / numparts;
4372 maxter = AM.MaxTer/sizeof(WORD);
4373 blocksize = ( workersize - maxter )/numberofblocks;
4374 numberofterms = blocksize / maxter;
4375 if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
4376/*
4377 This should have been taken care of in RecalcSetups.
4378*/
4379/* INTERNAL_ERROR_EXCL_START */
4380 MesPrint("!>We have a problem with the size of the blocks in IniSortBlocks");
4381 Terminate(-1);
4382/* INTERNAL_ERROR_EXCL_STOP */
4383 }
4384/*
4385 Layout: For each worker
4386 block 0: size is maxter WORDS
4387 numberofblocks blocks of size blocksize WORDS
4388*/
4389 w = S->lBuffer;
4390 if ( w == 0 ) w = S->sBuffer;
4391 for ( id = 1; id <= numparts; id++ ) {
4392 B = AB[id];
4393 AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
4394 sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
4395 AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
4396 AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
4397 AT.SB.MasterStop = AT.SB.MasterFill + (numberofblocks+1);
4398 AT.SB.MasterNumBlocks = numberofblocks;
4399 AT.SB.BlockTerms = (LONG*)Malloc1(sizeof(LONG)*(numberofblocks+1),"BlockTerms");
4400 AT.SB.MasterBlock = 0;
4401 AT.SB.FillBlock = 0;
4402 AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
4403 AT.SB.BlockTerms[0] = 0;
4404 w += maxter;
4405 AT.SB.MasterStop[0] = w;
4406 AT.SB.MasterBlockLock[0] = dummylock;
4407 for ( j = 1; j <= numberofblocks; j++ ) {
4408 AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
4409 AT.SB.BlockTerms[j] = 0;
4410 w += blocksize;
4411 AT.SB.MasterStop[j] = w;
4412 AT.SB.MasterBlockLock[j] = dummylock;
4413 }
4414 }
4415 if ( w > S->sTop2 ) {
4416/* INTERNAL_ERROR_EXCL_START */
4417 MesPrint("!>Counting problem in IniSortBlocks");
4418 Terminate(-1);
4419/* INTERNAL_ERROR_EXCL_STOP */
4420 }
4421 return(0);
4422}
4423
4424/*
4425 #] IniSortBlocks :
4426 #[ UpdateSortBlocks :
4427*/
4428
4433int UpdateSortBlocks(int numworkers)
4434{
4435 ALLPRIVATES *B;
4436 SORTING *S;
4437 LONG totalsize, workersize, blocksize, numberofterms;
4438 int maxter, id, j;
4439 int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
4440 WORD *w;
4441
4442 if ( numworkers == 0 ) return(0);
4443
4444 if ( GetNumberOfSortBots(numworkers) > 0) {
4445 numparts = numworkers + GetNumberOfSortBots(numberofworkers);
4446 numberofblocks = numberofblocks/2;
4447 }
4448 else {
4449 numparts = numworkers;
4450 }
4451 S = AM.S0;
4452 totalsize = S->LargeSize + S->SmallEsize;
4453 workersize = totalsize / numparts;
4454 maxter = AM.MaxTer/sizeof(WORD);
4455 blocksize = ( workersize - maxter )/numberofblocks;
4456 numberofterms = blocksize / maxter;
4457 if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
4458/*
4459 This should have been taken care of in RecalcSetups.
4460*/
4461/* INTERNAL_ERROR_EXCL_START */
4462 MesPrint("!>We have a problem with the size of the blocks in UpdateSortBlocks");
4463 Terminate(-1);
4464/* INTERNAL_ERROR_EXCL_STOP */
4465 }
4466/*
4467 Layout: For each worker
4468 block 0: size is maxter WORDS
4469 numberofblocks blocks of size blocksize WORDS
4470*/
4471 w = S->lBuffer;
4472 if ( w == 0 ) w = S->sBuffer;
4473 for ( id = 1; id <= numparts; id++ ) {
4474 B = AB[id];
4475 AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
4476 w += maxter;
4477 AT.SB.MasterStop[0] = w;
4478 for ( j = 1; j <= numberofblocks; j++ ) {
4479 AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
4480 w += blocksize;
4481 AT.SB.MasterStop[j] = w;
4482 }
4483 }
4484 if ( w > S->sTop2 ) {
4485/* INTERNAL_ERROR_EXCL_START */
4486 MesPrint("!>Counting problem in UpdateSortBlocks");
4487 Terminate(-1);
4488/* INTERNAL_ERROR_EXCL_STOP */
4489 }
4490 return(0);
4491}
4492
4493/*
4494 #] UpdateSortBlocks :
4495 #[ DefineSortBotTree :
4496*/
4497
4498
4504void DefineSortBotTree(void)
4505{
4506 ALLPRIVATES *B;
4507 int n, i, from;
4508 n = numberofworkers+GetNumberOfSortBots(numberofworkers);
4509 for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
4510 B = AB[i];
4511 AT.SortBotIn1 = from++;
4512 AT.SortBotIn2 = from++;
4513 }
4514 B = AB[0];
4515 AT.SortBotIn1 = from++;
4516 AT.SortBotIn2 = -1;
4517}
4518
4519
4520/*
4521 #] DefineSortBotTree :
4522 #[ GetTerm2 :
4523
4524 Routine does a GetTerm but only when a bracket index is involved and
4525 only from brackets that have been judged not suitable for treatment
4526 as complete brackets by a single worker. Whether or not a bracket should
4527 be treated by a single worker is decided by TreatIndexEntry
4528*/
4529
4530WORD GetTerm2(PHEAD WORD *term)
4531{
4532 WORD *ttco, *tt, retval;
4533 LONG n,i;
4534 FILEHANDLE *fi;
4535 EXPRESSIONS e = AN.expr;
4536 BRACKETINFO *b = e->bracketinfo;
4537 BRACKETINDEX *bi = b->indexbuffer;
4538 POSITION where, eonfile = AS.OldOnFile[e-Expressions], bstart, bnext;
4539/*
4540 1: Get the current position.
4541*/
4542 switch ( e->status ) {
4543 case UNHIDELEXPRESSION:
4544 case UNHIDEGEXPRESSION:
4545 case DROPHLEXPRESSION:
4546 case DROPHGEXPRESSION:
4547 case HIDDENLEXPRESSION:
4548 case HIDDENGEXPRESSION:
4549 fi = AR.hidefile;
4550 break;
4551 default:
4552 fi = AR.infile;
4553 break;
4554 }
4555 if ( AR.KeptInHold ) {
4556 retval = GetTerm(BHEAD term);
4557 return(retval);
4558 }
4559 SeekScratch(fi,&where);
4560 if ( AN.lastinindex < 0 ) {
4561/*
4562 We have to test whether we have to do the first bracket
4563*/
4564 if ( ( n = TreatIndexEntry(BHEAD 0) ) <= 0 ) {
4565 AN.lastinindex = n;
4566 where = bi[n].start;
4567 ADD2POS(where,eonfile);
4568 SetScratch(fi,&where);
4569/*
4570 Put the bracket in the Compress buffer.
4571*/
4572 ttco = AR.CompressBuffer;
4573 tt = b->bracketbuffer + bi[0].bracket;
4574 i = *tt;
4575 NCOPY(ttco,tt,i)
4576 AR.CompressPointer = ttco;
4577 retval = GetTerm(BHEAD term);
4578 return(retval);
4579 }
4580 else AN.lastinindex = n-1;
4581 }
4582/*
4583 2: Find the corresponding index number
4584 a: test whether it is in the current bracket
4585*/
4586 n = AN.lastinindex;
4587 bstart = bi[n].start;
4588 ADD2POS(bstart,eonfile);
4589 bnext = bi[n].next;
4590 ADD2POS(bnext,eonfile);
4591 if ( ISLESSPOS(bstart,where) && ISLESSPOS(where,bnext) ) {
4592 retval = GetTerm(BHEAD term);
4593 return(retval);
4594 }
4595 for ( n++ ; n < b->indexfill; n++ ) {
4596 i = TreatIndexEntry(BHEAD n);
4597 if ( i <= 0 ) {
4598/*
4599 Put the bracket in the Compress buffer.
4600*/
4601 ttco = AR.CompressBuffer;
4602 tt = b->bracketbuffer + bi[n].bracket;
4603 i = *tt;
4604 NCOPY(ttco,tt,i)
4605 AR.CompressPointer = ttco;
4606 AN.lastinindex = n;
4607 where = bi[n].start;
4608 ADD2POS(where,eonfile);
4609 SetScratch(fi,&(where));
4610 retval = GetTerm(BHEAD term);
4611 return(retval);
4612 }
4613 else n += i - 1;
4614 }
4615 return(0);
4616}
4617
4618/*
4619 #] GetTerm2 :
4620 #[ TreatIndexEntry :
4621*/
4630int TreatIndexEntry(PHEAD LONG n)
4631{
4632 BRACKETINFO *b = AN.expr->bracketinfo;
4633 LONG numbra = b->indexfill - 1, i;
4634 LONG totterms;
4635 BRACKETINDEX *bi;
4636 POSITION pos1, average;
4637/*
4638 1: number of the bracket should be such that there is one bucket
4639 for each worker remaining.
4640*/
4641 if ( ( numbra - n ) <= numberofworkers ) return(0);
4642/*
4643 2: size of the bracket contents should be less than what remains in
4644 the expression divided by the number of workers.
4645*/
4646 bi = b->indexbuffer;
4647 DIFPOS(pos1,bi[numbra].next,bi[n].next); /* Size of what remains */
4648 BASEPOSITION(average) = DIVPOS(pos1,(3*numberofworkers));
4649 DIFPOS(pos1,bi[n].next,bi[n].start); /* Size of the current bracket */
4650 if ( ISLESSPOS(average,pos1) ) return(0);
4651/*
4652 It passes.
4653 Now check whether we can do more brackets
4654*/
4655 totterms = bi->termsinbracket;
4656 if ( totterms > 2*AC.ThreadBucketSize ) return(1);
4657 for ( i = 1; i < numbra-n; i++ ) {
4658 DIFPOS(pos1,bi[n+i].next,bi[n].start); /* Size of the combined brackets */
4659 if ( ISLESSPOS(average,pos1) ) return(i);
4660 totterms += bi->termsinbracket;
4661 if ( totterms > 2*AC.ThreadBucketSize ) return(i+1);
4662 }
4663/*
4664 We have a problem at the end of the system. Just do one.
4665*/
4666 return(1);
4667}
4668
4669/*
4670 #] TreatIndexEntry :
4671 #[ SetHideFiles :
4672*/
4673
4674void SetHideFiles(void) {
4675 int i;
4676 ALLPRIVATES *B, *B0 = AB[0];
4677 for ( i = 1; i <= numberofworkers; i++ ) {
4678 B = AB[i];
4679 AR.hidefile->handle = AR0.hidefile->handle;
4680 if ( AR.hidefile->handle < 0 ) {
4681 AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
4682 AR.hidefile->POstop = AR0.hidefile->POstop;
4683 AR.hidefile->POfill = AR0.hidefile->POfill;
4684 AR.hidefile->POfull = AR0.hidefile->POfull;
4685 AR.hidefile->POsize = AR0.hidefile->POsize;
4686 AR.hidefile->POposition = AR0.hidefile->POposition;
4687 AR.hidefile->filesize = AR0.hidefile->filesize;
4688 }
4689 else {
4690 AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
4691 AR.hidefile->POstop = AR.hidefile->wPOstop;
4692 AR.hidefile->POfill = AR.hidefile->wPOfill;
4693 AR.hidefile->POfull = AR.hidefile->wPOfull;
4694 AR.hidefile->POsize = AR.hidefile->wPOsize;
4695 PUTZERO(AR.hidefile->POposition);
4696 }
4697 }
4698}
4699
4700/*
4701 #] SetHideFiles :
4702 #[ IniFbufs :
4703*/
4704
4705void IniFbufs(void)
4706{
4707 int i;
4708 for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
4709 IniFbuffer(AB[i]->T.fbufnum);
4710 }
4711}
4712
4713/*
4714 #] IniFbufs :
4715 #[ SetMods :
4716*/
4717
4718void SetMods(void)
4719{
4720 ALLPRIVATES *B;
4721 int i, n, j;
4722 for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
4723 B = AB[j];
4724 AN.ncmod = AC.ncmod;
4725 if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
4726 n = ABS(AN.ncmod);
4727 AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
4728 for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
4729 }
4730}
4731
4732/*
4733 #] SetMods :
4734 #[ UnSetMods :
4735*/
4736
4737void UnSetMods(void)
4738{
4739 ALLPRIVATES *B;
4740 int j;
4741 for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
4742 B = AB[j];
4743 if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
4744 AN.cmod = 0;
4745 }
4746}
4747
4748/*
4749 #] UnSetMods :
4750 #[ find_Horner_MCTS_expand_tree_threaded :
4751*/
4752
4753void find_Horner_MCTS_expand_tree_threaded(void) {
4754 int id;
4755 while (( id = GetAvailableThread() ) < 0)
4756 MasterWait();
4757 WakeupThread(id,MCTSEXPANDTREE);
4758}
4759
4760/*
4761 #] find_Horner_MCTS_expand_tree_threaded :
4762 #[ optimize_expression_given_Horner_threaded :
4763*/
4764
4765extern void optimize_expression_given_Horner_threaded(void) {
4766 int id;
4767 while (( id = GetAvailableThread() ) < 0)
4768 MasterWait();
4769 WakeupThread(id,OPTIMIZEEXPRESSION);
4770}
4771
4772/*
4773 #] optimize_expression_given_Horner_threaded :
4774*/
4775
4776#endif
int inicbufs(void)
Definition comtool.c:47
int IniFbuffer(WORD bufnum)
Definition comtool.c:612
void AddArgs(PHEAD WORD *, WORD *, WORD *)
Definition sort.c:2098
WORD * poly_ratfun_add(PHEAD WORD *, WORD *)
Definition polywrap.cc:635
int poly_unfactorize_expression(EXPRESSIONS)
Definition polywrap.cc:1545
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition sort.c:1217
LONG EndSort(PHEAD WORD *, int)
Definition sort.c:488
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3272
void LowerSortLevel(void)
Definition sort.c:4731
int StoreTerm(PHEAD WORD *)
Definition sort.c:4311
int poly_factorize_expression(EXPRESSIONS)
Definition polywrap.cc:1180
void WriteStats(POSITION *, WORD, WORD)
Definition sort.c:138
int NewSort(PHEAD0)
Definition sort.c:397
int NormalModulus(UWORD *, WORD *)
Definition reken.c:1416
int FlushOut(POSITION *, FILEHANDLE *, int)
Definition sort.c:1581
WORD Compare1(PHEAD WORD *, WORD *, WORD)
Definition sort.c:2393
LONG TimeCPU(WORD)
Definition tools.c:3499
void optimize_expression_given_Horner()
Definition optimize.cc:4060
BRACKETINDEX * indexbuffer
Definition structs.h:323
WORD * bracketbuffer
Definition structs.h:324
WORD ** rhs
Definition structs.h:975
WORD ** lhs
Definition structs.h:974
WORD * Buffer
Definition structs.h:971
WORD * Pointer
Definition structs.h:973
int handle
Definition structs.h:709
struct NeStInG * NESTING
struct StOrEcAcHe * STORECACHE