• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

form-dev / form / 17338759957

30 Aug 2025 03:23AM UTC coverage: 53.727% (+0.03%) from 53.699%
17338759957

Pull #622

github

web-flow
Merge 5fd2e3d04 into e3eeea38a
Pull Request #622: ci(refactor): extract build setup logic into setup-build

44721 of 83237 relevant lines covered (53.73%)

2235137.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.02
/sources/threads.c
1
/** @file threads.c
2
 * 
3
 *  Routines for the interface of FORM with the pthreads library
4
 *
5
 *        This is the main part of the parallelization of TFORM.
6
 *        It is important to also look in the files structs.h and variable.h
7
 *        because the treatment of the A and B structs is essential (these
8
 *        structs are used by means of the macros AM, AP, AC, AS, AR, AT, AN,
9
 *        AO and AX). Also the definitions and use of the macros BHEAD and PHEAD
10
 *        should be looked up.
11
 *
12
 *        The sources are set up in such a way that if WITHPTHREADS isn't defined
13
 *        there is no trace of pthread parallelization.
14
 *        The reason is that TFORM is far more memory hungry than sequential FORM.
15
 *
16
 *        Special attention should also go to the locks. The proper use of the
17
 *        locks is essential and determines whether TFORM can work at all.
18
 *        We use the LOCK/UNLOCK macros which are empty in the case of sequential FORM
19
 *        These locks are at many places in the source files when workers can
20
 *        interfere with each others data or with the data of the master.
21
 */
22
/* #[ License : */
23
/*
24
 *   Copyright (C) 1984-2023 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 (MasterMerge)
59
        is much simpler for the sortbots. On the other hand the original merging is
60
        for a large part a copy of the MergePatches routine in sort.c and hence
61
        even though complex the bad part has been thoroughly debugged.
62
*/
63

64
#include "form3.h"
65

66
#ifdef WITH_ALARM
67
// This is only required if we are blocking SIG_ALRM in the worker threads.
68
#include <signal.h>
69
#endif
70

71
#ifdef WITHFLOAT
72
#include <gmp.h>
73

74
int PackFloat(WORD *,mpf_t);
75
int UnpackFloat(mpf_t, WORD *);
76
void RatToFloat(mpf_t result, UWORD *formrat, int ratsize);
77
#endif
78
 
79
static int numberofthreads;
80
static int numberofworkers;
81
static int identityofthreads = 0;
82
static int *listofavailables;
83
static int topofavailables = 0;
84
static pthread_key_t identitykey;
85
static INILOCK(numberofthreadslock)
86
static INILOCK(availabilitylock)
87
static pthread_t *threadpointers = 0;
88
static pthread_mutex_t *wakeuplocks;
89
static pthread_mutex_t *wakeupmasterthreadlocks;
90
static pthread_cond_t *wakeupconditions;
91
static pthread_condattr_t *wakeupconditionattributes;
92
static int *wakeup;
93
static int *wakeupmasterthread;
94
static INILOCK(wakeupmasterlock)
95
static pthread_cond_t wakeupmasterconditions = PTHREAD_COND_INITIALIZER;
96
static pthread_cond_t *wakeupmasterthreadconditions;
97
static int wakeupmaster = 0;
98
static int identityretval;
99
/* static INILOCK(clearclocklock) */
100
static LONG *timerinfo;
101
static LONG *sumtimerinfo;
102
static int numberclaimed;
103

104
static THREADBUCKET **threadbuckets, **freebuckets;
105
static int numthreadbuckets;
106
static int numberoffullbuckets;
107

108
/* static int numberbusy = 0; */
109

110
INILOCK(dummylock)
111
INIRWLOCK(dummyrwlock)
112
static pthread_cond_t dummywakeupcondition = PTHREAD_COND_INITIALIZER;
113

114
#ifdef WITHSORTBOTS
115
static POSITION SortBotPosition;
116
static int numberofsortbots;
117
static INILOCK(wakeupsortbotlock)
118
static pthread_cond_t wakeupsortbotconditions = PTHREAD_COND_INITIALIZER;
119
static int topsortbotavailables = 0;
120
static LONG numberofterms;
121
#endif
122

123
/*
124
          #] Variables : 
125
          #[ Identity :
126
                 #[ StartIdentity :
127
*/
128
/**
129
 *        To be called once when we start up the threads.
130
 *        Starts our identity administration.
131
 */
132

133
void StartIdentity(void)
1,564✔
134
{
135
        pthread_key_create(&identitykey,FinishIdentity);
1,564✔
136
}
1,564✔
137

138
/*
139
                 #] StartIdentity : 
140
                 #[ FinishIdentity :
141
*/
142
/**
143
 *        The library needs a finishing routine
144
 */
145

146
void FinishIdentity(void *keyp)
5,408✔
147
{
148
        DUMMYUSE(keyp);
5,408✔
149
/*        free(keyp); */
150
}
5,408✔
151

152
/*
153
                 #] FinishIdentity : 
154
                 #[ SetIdentity :
155
*/
156
/**
157
 *        Assigns an integer value to a thread, starting at zero.
158
 */
159

160
int SetIdentity(int *identityretval)
7,740✔
161
{
162
/*
163
#ifdef _MSC_VER
164
        printf("addr %d\n",&numberofthreadslock);
165
        printf("size %d\n",sizeof(numberofthreadslock));
166
#endif
167
*/
168
        LOCK(numberofthreadslock);
7,740✔
169
        *identityretval = identityofthreads++;
7,740✔
170
        UNLOCK(numberofthreadslock);
7,740✔
171
        pthread_setspecific(identitykey,(void *)identityretval);
7,740✔
172
        return(*identityretval);
7,740✔
173
}
174

175
/*
176
                 #] SetIdentity : 
177
                 #[ WhoAmI :
178
*/
179

180
/**
181
 *        Returns the number of the current thread in our administration
182
 *
183
 *        This routine is to be called in routines that need access to the thread
184
 *        specific data and that don't get their B-struct passed as an argument.
185
 *        Routines that get called frequently need their B-struct passed.
186
 *        This is done with BHEAD and the argumentfield gets declared with
187
 *        one of the BARG macros rather than the ARG macros.
188
 */
189

190
int WhoAmI(void)
57,993,000✔
191
{
192
        int *identity;
57,993,000✔
193
/*
194
        First a fast exit for when there is at most one thread
195
*/
196
        if ( identityofthreads <= 1 ) return(0);
57,993,000✔
197
/*
198
        Now the reading of the key.
199
        According to the book the statement should read:
200

201
        pthread_getspecific(identitykey,(void **)(&identity));
202

203
        but according to the information in pthread.h it is:
204
*/
205
        identity = (int *)pthread_getspecific(identitykey);
57,989,408✔
206
        return(*identity);
57,989,408✔
207
}
208

209
/*
210
                 #] WhoAmI : 
211
                 #[ BeginIdentities :
212
*/
213
/**
214
 *        Starts up the identity registration. This is the routine to be called
215
 *        at the startup of TFORM.
216
 */
217

218
void BeginIdentities(void)
1,564✔
219
{
220
        StartIdentity();
1,564✔
221
        SetIdentity(&identityretval);
1,564✔
222
}
1,564✔
223

224
/*
225
                 #] BeginIdentities : 
226
          #] Identity : 
227
          #[ StartHandleLock :
228
*/
229
/**
230
 *        Routine to be called at the startup of TFORM.
231
 *        We have this routine because we would like to keep all access to TFORM
232
 *        specific data in this file.
233
 */
234

235
void StartHandleLock(void)
1,564✔
236
{
237
        AM.handlelock = dummyrwlock;
1,564✔
238
}
1,564✔
239

240
/*
241
          #] StartHandleLock : 
242
          #[ StartAllThreads :
243
*/
244
/**
245
 *        In this routine we start 'number' threads.
246
 *        The routine that runs the show for each worker is called RunThread.
247
 *        It will call the allocations and all the worker specific action.
248
 *        Then the master has to wait till all workers are asleep before continuing.
249
 *        If we use SortBots (special threads to help the master during the
250
 *        final stages of a big sort) they are started and their routine is
251
 *        called RunSortBot.
252
 *        The master then waits till all sortbots are asleep before continuing.
253
 *        Finally the sort buffers of the master are parcelled up for the final
254
 *        merge in big sorts in which the workers have to feed the master.
255
 *
256
 *        @param number The number of main threads (including the master)
257
 *                      The number of workers is number-1.
258
 *        @return  Standard return conventions (OK -> 0)
259
 */
260

261
int StartAllThreads(int number)
1,560✔
262
{
263
        int identity, j, dummy, mul;
1,560✔
264
        ALLPRIVATES *B;
1,560✔
265
        pthread_t thethread;
1,560✔
266
        identity = WhoAmI();
1,560✔
267

268
#ifdef WITHSORTBOTS
269
        timerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"timerinfo");
1,560✔
270
        sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"sumtimerinfo");
1,560✔
271
        for ( j = 0; j < number*2; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
13,944✔
272
        mul = 2;
1,560✔
273
#else
274
        timerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"timerinfo");
275
        sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"sumtimerinfo");
276
        for ( j = 0; j < number; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
277
        mul = 1;
278
#endif
279
 
280
        listofavailables = (int *)Malloc1(sizeof(int)*(number+1),"listofavailables");
1,560✔
281
        threadpointers = (pthread_t *)Malloc1(sizeof(pthread_t)*number*mul,"threadpointers");
1,560✔
282
        AB = (ALLPRIVATES **)Malloc1(sizeof(ALLPRIVATES *)*number*mul,"Private structs");
1,560✔
283

284
        wakeup = (int *)Malloc1(sizeof(int)*number*mul,"wakeup");
1,560✔
285
        wakeuplocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeuplocks");
1,560✔
286
        wakeupconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupconditions");
1,560✔
287
        wakeupconditionattributes = (pthread_condattr_t *)
3,120✔
288
                        Malloc1(sizeof(pthread_condattr_t)*number*mul,"wakeupconditionattributes");
1,560✔
289

290
        wakeupmasterthread = (int *)Malloc1(sizeof(int)*number*mul,"wakeupmasterthread");
1,560✔
291
        wakeupmasterthreadlocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeupmasterthreadlocks");
1,560✔
292
        wakeupmasterthreadconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupmasterthread");
1,560✔
293

294
        numberofthreads = number;
1,560✔
295
        numberofworkers = number - 1;
1,560✔
296
        threadpointers[identity] = pthread_self();
1,560✔
297
        topofavailables = 0;
1,560✔
298

299
#ifdef WITH_ALARM
300
        /* During thread creation, we block SIGALRM on the main thread. The created
301
           threads will inherit this. This is required for #timeout to work properly
302
           in TFORM: only the main thread should recieve SIGALRM. */
303
        sigset_t sig_set;
1,560✔
304
        sigemptyset(&sig_set);
1,560✔
305
        sigaddset(&sig_set, SIGALRM);
1,560✔
306
        pthread_sigmask(SIG_BLOCK, &sig_set, NULL);
1,560✔
307
#endif
308

309
        for ( j = 1; j < number; j++ ) {
7,752✔
310
                if ( pthread_create(&thethread,NULL,RunThread,(void *)(&dummy)) )
4,632✔
311
                        goto failure;
×
312
        }
313
/*
314
        Now we initialize the master at the same time that the workers are doing so.
315
*/
316
        B = InitializeOneThread(identity);
1,560✔
317
        AR.infile = &(AR.Fscr[0]);
1,560✔
318
        AR.outfile = &(AR.Fscr[1]);
1,560✔
319
        AR.hidefile = &(AR.Fscr[2]);
1,560✔
320
        AM.sbuflock = dummylock;
1,560✔
321
        AS.inputslock = dummylock;
1,560✔
322
        AS.outputslock = dummylock;
1,560✔
323
        AS.MaxExprSizeLock = dummylock;
1,560✔
324
        AP.PreVarLock = dummylock;
1,560✔
325
        AC.halfmodlock = dummylock;
1,560✔
326
        MakeThreadBuckets(number,0);
1,560✔
327
/*
328
        Now we wait for the workers to finish their startup.
329
        We don't want to initialize the sortbots yet and run the risk that 
330
        some of them may end up with a lower number than one of the workers.
331
*/
332
        MasterWaitAll();
1,560✔
333
#ifdef WITHSORTBOTS
334
        if ( numberofworkers > 2 ) {
1,560✔
335
                numberofsortbots = numberofworkers-2;
772✔
336
                for ( j = numberofworkers+1; j < 2*numberofworkers-1; j++ ) {
2,316✔
337
                        if ( pthread_create(&thethread,NULL,RunSortBot,(void *)(&dummy)) )
1,544✔
338
                                goto failure;
×
339
                }
340
        }
341
        else {
342
                numberofsortbots = 0;
788✔
343
        }
344
        MasterWaitAllSortBots();
1,560✔
345
        DefineSortBotTree();
1,560✔
346
#endif
347
        IniSortBlocks(number-1);
1,560✔
348
        AS.MasterSort = 0;
1,560✔
349
        AM.storefilelock = dummylock;
1,560✔
350

351
#ifdef WITH_ALARM
352
        /* Now we allow the main thread to recieve SIGALRM again. */
353
        pthread_sigmask(SIG_UNBLOCK, &sig_set, NULL);
1,560✔
354
#endif
355

356
/*
357
MesPrint("AB = %x %x %x  %d",AB[0],AB[1],AB[2], identityofthreads);
358
*/
359
        return(0);
1,560✔
360
failure:
×
361
        MesPrint("Cannot start %d threads",number);
×
362
        Terminate(-1);
×
363
        return(-1);
×
364
}
365

366
/*
367
          #] StartAllThreads : 
368
          #[ InitializeOneThread :
369
*/
370
/**
371
 *        Array for putting a label on memory allocations and error messages.
372
 */
373
UBYTE *scratchname[] = { (UBYTE *)"scratchsize",
374
                         (UBYTE *)"scratchsize",
375
                         (UBYTE *)"hidesize" };
376
/**
377
 *        Initializes one thread. This includes the allocation of its private
378
 *        space and all its buffers. Also the initialization of variables.
379
 *
380
 *        @param identity The (TFORM defined) integer identifier of the thread.
381
 *        @return A pointer to the struct with all private data of the thread.
382
 *        We call this struct B and we have a system of macros
383
 *        (defined in variable.h) that allows us to access its substructs in
384
 *        the same way as the corresponding substructs in sequential FORM are
385
 *        accessed. Example:
386
 *                In TFORM  AR is defined as B->R
387
 *                In FORM   AR is defined as A.R  (here it is part of the A struct)
388
 *
389
 *        One complication:
390
 *                AM.ScratSize can be rather big. We don't want all the workers
391
 *                to have an allocation of that size. Some computers may run out
392
 *                of allocations.
393
 *                We need on the workers:
394
 *                        AR.Fscr[0] : input for keep brackets and expressions in rhs
395
 *                        AR.Fscr[1] : output of the sorting to be fed to the master
396
 *                        AR.Fscr[2] : input for keep brackets and expressions in rhs
397
 *                Hence the 0 and 2 channels can use a rather small buffer like
398
 *                        10*AM.MaxTer.
399
 *                The 1 channel needs a buffer roughly AM.ScratSize/#ofworkers.
400
 */
401

402
ALLPRIVATES *InitializeOneThread(int identity)
7,736✔
403
{
404
        WORD *t, *ScratchBuf;
7,736✔
405
        int i, j, bsize, *bp;
7,736✔
406
        LONG ScratchSize[3], IOsize;
7,736✔
407
        ALLPRIVATES *B;
7,736✔
408
        UBYTE *s;
7,736✔
409

410
        wakeup[identity] = 0;
7,736✔
411
        wakeuplocks[identity] = dummylock;
7,736✔
412
        pthread_condattr_init(&(wakeupconditionattributes[identity]));
7,736✔
413
        pthread_condattr_setpshared(&(wakeupconditionattributes[identity]),PTHREAD_PROCESS_PRIVATE);
7,736✔
414
        wakeupconditions[identity] = dummywakeupcondition;
7,736✔
415
        pthread_cond_init(&(wakeupconditions[identity]),&(wakeupconditionattributes[identity]));
7,736✔
416
        wakeupmasterthread[identity] = 0;
7,736✔
417
        wakeupmasterthreadlocks[identity] = dummylock;
7,736✔
418
        wakeupmasterthreadconditions[identity] = dummywakeupcondition;
7,736✔
419

420
        bsize = sizeof(ALLPRIVATES);
7,736✔
421
        bsize = (bsize+sizeof(int)-1)/sizeof(int);
7,736✔
422
        B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
7,736✔
423
        for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
46,060,144✔
424

425
        AB[identity] = B;
7,736✔
426
/*
427
                        12-jun-2007 JV:
428
        For the timing one has to know a few things:
429
        The POSIX standard is that there is only a single process ID and that
430
        getrusage returns the time of all the threads together.
431
        Under Linux there are two methods though: The older LinuxThreads and NPTL.
432
        LinuxThreads gives each thread its own process id. This makes that we
433
        can time the threads with getrusage, and hence this was done. Under NPTL
434
        this has been 'corrected' and suddenly getruage doesn't work anymore the
435
        way it used to. Now we need
436
                clock_gettime(CLOCK_THREAD_CPUTIME_ID,&timing)
437
        which is declared in <time.h> and we need -lrt extra in the link statement.
438
        (this is at least the case on blade02 at DESY-Zeuthen).
439
        See also the code in tools.c at the routine Timer.
440
        We may still have to include more stuff there.
441
*/
442
        if ( identity > 0 ) TimeCPU(0);
7,736✔
443

444
#ifdef WITHSORTBOTS
445

446
        if ( identity > numberofworkers ) {
7,736✔
447
/*
448
                Some workspace is needed when we have a PolyFun and we have to add
449
                two terms and the new result is going to be longer than the old result.
450
*/
451
                LONG length = AM.WorkSize*sizeof(WORD)/8+AM.MaxTer*2;
1,544✔
452
                AT.WorkSpace = (WORD *)Malloc1(length,"WorkSpace");
1,544✔
453
                AT.WorkTop = AT.WorkSpace + length/sizeof(WORD);
1,544✔
454
                AT.WorkPointer = AT.WorkSpace;
1,544✔
455
                AT.identity = identity;
1,544✔
456
/*
457
                The SB struct gets treated in IniSortBlocks.
458
                The SortBotIn variables will be defined DefineSortBotTree.
459
*/
460
                if ( AN.SoScratC == 0 ) {
1,544✔
461
                        AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
1,544✔
462
                }
463
                AT.SS = (SORTING *)Malloc1(sizeof(SORTING),"dummy sort buffer");
1,544✔
464
                AT.SS->PolyFlag = 0;
1,544✔
465

466
                AT.comsym[0] = 8;
1,544✔
467
                AT.comsym[1] = SYMBOL;
1,544✔
468
                AT.comsym[2] = 4;
1,544✔
469
                AT.comsym[3] = 0;
1,544✔
470
                AT.comsym[4] = 1;
1,544✔
471
                AT.comsym[5] = 1;
1,544✔
472
                AT.comsym[6] = 1;
1,544✔
473
                AT.comsym[7] = 3;
1,544✔
474
                AT.comnum[0] = 4;
1,544✔
475
                AT.comnum[1] = 1;
1,544✔
476
                AT.comnum[2] = 1;
1,544✔
477
                AT.comnum[3] = 3;
1,544✔
478
                AT.comfun[0] = FUNHEAD+4;
1,544✔
479
                AT.comfun[1] = FUNCTION;
1,544✔
480
                AT.comfun[2] = FUNHEAD;
1,544✔
481
                AT.comfun[3] = 0;
1,544✔
482
#if FUNHEAD > 3
483
                for ( i = 4; i <= FUNHEAD; i++ )
484
                        AT.comfun[i] = 0;
485
#endif
486
                AT.comfun[FUNHEAD+1] = 1;
1,544✔
487
                AT.comfun[FUNHEAD+2] = 1;
1,544✔
488
                AT.comfun[FUNHEAD+3] = 3;
1,544✔
489
                AT.comind[0] = 7;
1,544✔
490
                AT.comind[1] = INDEX;
1,544✔
491
                AT.comind[2] = 3;
1,544✔
492
                AT.comind[3] = 0;
1,544✔
493
                AT.comind[4] = 1;
1,544✔
494
                AT.comind[5] = 1;
1,544✔
495
                AT.comind[6] = 3;
1,544✔
496

497
                AT.inprimelist = -1;
1,544✔
498
                AT.sizeprimelist = 0;
1,544✔
499
                AT.primelist = 0;
1,544✔
500
                AT.bracketinfo = 0;
1,544✔
501
                
502
                AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
1,544✔
503

504
                AR.sLevel = 0;
1,544✔
505
                AR.wranfia = 0;
1,544✔
506
                AR.wranfcall = 0;
1,544✔
507
                AR.wranfnpair1 = NPAIR1;
1,544✔
508
                AR.wranfnpair2 = NPAIR2;
1,544✔
509
                AN.NumFunSorts = 5;
1,544✔
510
                AN.MaxFunSorts = 5;
1,544✔
511
                AN.SplitScratch = 0;
1,544✔
512
                AN.SplitScratchSize = AN.InScratch = 0;
1,544✔
513
                AN.SplitScratch1 = 0;
1,544✔
514
                AN.SplitScratchSize1 = AN.InScratch1 = 0;
1,544✔
515

516
                AN.FunSorts = (SORTING **)Malloc1((AN.NumFunSorts+1)*sizeof(SORTING *),"FunSort pointers");
1,544✔
517
                for ( i = 0; i <= AN.NumFunSorts; i++ ) AN.FunSorts[i] = 0;
10,808✔
518
                AN.FunSorts[0] = AT.S0 = AT.SS;
1,544✔
519
                AN.idfunctionflag = 0;
1,544✔
520
                AN.tryterm = 0;
1,544✔
521

522
                return(B);
1,544✔
523
        }
524
        if ( identity == 0 && AN.SoScratC == 0 ) {
6,192✔
525
                AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
1,560✔
526
        }
527
#endif
528
        AR.CurDum = AM.IndDum;
6,192✔
529
        for ( j = 0; j < 3; j++ ) {
24,768✔
530
                if ( identity == 0 ) {
18,576✔
531
                        if ( j == 2 ) {
4,680✔
532
                                ScratchSize[j] = AM.HideSize;
1,560✔
533
                        }
534
                        else {
535
                                ScratchSize[j] = AM.ScratSize;
3,120✔
536
                        }
537
                        if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
4,680✔
538
                }
539
                else {
540
/*
541
                        ScratchSize[j] = AM.ScratSize / (numberofthreads-1);
542
                        ScratchSize[j] = ScratchSize[j] / 20;
543
                        if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
544
*/
545
                        if ( j == 1 ) ScratchSize[j] = AM.ThreadScratOutSize;
13,896✔
546
                        else          ScratchSize[j] = AM.ThreadScratSize;
9,264✔
547
                        if ( ScratchSize[j] < 4*AM.MaxTer ) ScratchSize[j] = 4 * AM.MaxTer;
13,896✔
548
                        AR.Fscr[j].name = 0;
13,896✔
549
                }
550
                ScratchSize[j] = ( ScratchSize[j] + 255 ) / 256;
18,576✔
551
                ScratchSize[j] = ScratchSize[j] * 256;
18,576✔
552
                ScratchBuf = (WORD *)Malloc1(ScratchSize[j]*sizeof(WORD),(char *)(scratchname[j]));
18,576✔
553
                AR.Fscr[j].POsize = ScratchSize[j] * sizeof(WORD);
18,576✔
554
                AR.Fscr[j].POfull = AR.Fscr[j].POfill = AR.Fscr[j].PObuffer = ScratchBuf;
18,576✔
555
                AR.Fscr[j].POstop = AR.Fscr[j].PObuffer + ScratchSize[j];
18,576✔
556
                PUTZERO(AR.Fscr[j].POposition);
18,576✔
557
                AR.Fscr[j].pthreadslock = dummylock;
18,576✔
558
                AR.Fscr[j].wPOsize = AR.Fscr[j].POsize;
18,576✔
559
                AR.Fscr[j].wPObuffer = AR.Fscr[j].PObuffer;
18,576✔
560
                AR.Fscr[j].wPOfill = AR.Fscr[j].POfill;
18,576✔
561
                AR.Fscr[j].wPOfull = AR.Fscr[j].POfull;
18,576✔
562
                AR.Fscr[j].wPOstop = AR.Fscr[j].POstop;
18,576✔
563
        }
564
        AR.InInBuf = 0;
6,192✔
565
        AR.InHiBuf = 0;
6,192✔
566
        AR.Fscr[0].handle = -1;
6,192✔
567
        AR.Fscr[1].handle = -1;
6,192✔
568
        AR.Fscr[2].handle = -1;
6,192✔
569
        AR.FoStage4[0].handle = -1;
6,192✔
570
        AR.FoStage4[1].handle = -1;
6,192✔
571
        IOsize = AM.S0->file.POsize;
6,192✔
572
#ifdef WITHZLIB
573
        AR.FoStage4[0].ziosize = IOsize;
6,192✔
574
        AR.FoStage4[1].ziosize = IOsize;
6,192✔
575
        AR.FoStage4[0].ziobuffer = 0;
6,192✔
576
        AR.FoStage4[1].ziobuffer = 0;
6,192✔
577
#endif        
578
        AR.FoStage4[0].POsize  = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
6,192✔
579
        AR.FoStage4[1].POsize  = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
6,192✔
580

581
        AR.hidefile = &(AR.Fscr[2]);
6,192✔
582
        AR.StoreData.Handle = -1;
6,192✔
583
        AR.SortType = AC.SortType;
6,192✔
584

585
        AN.IndDum = AM.IndDum;
6,192✔
586

587
        if ( identity > 0 ) {
6,192✔
588
                s = (UBYTE *)(FG.fname); i = 0;
4,632✔
589
                while ( *s ) { s++; i++; }
88,008✔
590
                s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[0] file");
4,632✔
591
                snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
4,632✔
592
                s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '0';
4,632✔
593
                AR.Fscr[0].name = (char *)s;
4,632✔
594
                s = (UBYTE *)(FG.fname); i = 0;
4,632✔
595
                while ( *s ) { s++; i++; }
88,008✔
596
                s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[1] file");
4,632✔
597
                snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
4,632✔
598
                s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '1';
4,632✔
599
                AR.Fscr[1].name = (char *)s;
4,632✔
600
        }
601

602
        AR.CompressBuffer = (WORD *)Malloc1((AM.CompressSize+10)*sizeof(WORD),"compresssize");
6,192✔
603
        AR.ComprTop = AR.CompressBuffer + AM.CompressSize;
6,192✔
604
        AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
6,192✔
605
/*
606
        Here we make all allocations for the struct AT
607
        (which is AB[identity].T or B->T with B = AB+identity).
608
*/
609
        AT.WorkSpace = (WORD *)Malloc1(AM.WorkSize*sizeof(WORD),"WorkSpace");
6,192✔
610
        AT.WorkTop = AT.WorkSpace + AM.WorkSize;
6,192✔
611
        AT.WorkPointer = AT.WorkSpace;
6,192✔
612

613
        AT.Nest = (NESTING)Malloc1((LONG)sizeof(struct NeStInG)*AM.maxFlevels,"functionlevels");
6,192✔
614
        AT.NestStop = AT.Nest + AM.maxFlevels;
6,192✔
615
        AT.NestPoin = AT.Nest;
6,192✔
616

617
        AT.WildMask = (WORD *)Malloc1((LONG)AM.MaxWildcards*sizeof(WORD),"maxwildcards");
6,192✔
618

619
        LOCK(availabilitylock);
6,192✔
620
        AT.ebufnum = inicbufs();                /* Buffer for extras during execution */
6,192✔
621
        AT.fbufnum = inicbufs();                /* Buffer for caching in factorization */
6,192✔
622
        AT.allbufnum = inicbufs();                /* Buffer for id,all */
6,192✔
623
        AT.aebufnum = inicbufs();                /* Buffer for id,all */
6,192✔
624
        UNLOCK(availabilitylock);
6,192✔
625

626
        AT.RepCount = (int *)Malloc1((LONG)((AM.RepMax+3)*sizeof(int)),"repeat buffers");
6,192✔
627
        AN.RepPoint = AT.RepCount;
6,192✔
628
        AN.polysortflag = 0;
6,192✔
629
        AN.subsubveto = 0;
6,192✔
630
        AN.tryterm = 0;
6,192✔
631
        AT.RepTop = AT.RepCount + AM.RepMax;
6,192✔
632

633
        AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
6,192✔
634
                                ,"argument list names");
635
        AT.WildcardBufferSize = AC.WildcardBufferSize;
6,192✔
636
        AT.previousEfactor = 0;
6,192✔
637

638
        AT.identity = identity;
6,192✔
639
        AT.LoadBalancing = 0;
6,192✔
640
/*
641
        Still to do: the SS stuff.
642
                     the Fscr[3]
643
                     the FoStage4[2]
644
*/
645
        if ( AT.WorkSpace == 0 ||
6,192✔
646
             AT.Nest == 0 ||
6,192✔
647
             AT.WildMask == 0 ||
6,192✔
648
             AT.RepCount == 0 ||
6,192✔
649
             AT.WildArgTaken == 0 ) goto OnError;
×
650
/*
651
        And initializations
652
*/
653
        AT.comsym[0] = 8;
6,192✔
654
        AT.comsym[1] = SYMBOL;
6,192✔
655
        AT.comsym[2] = 4;
6,192✔
656
        AT.comsym[3] = 0;
6,192✔
657
        AT.comsym[4] = 1;
6,192✔
658
        AT.comsym[5] = 1;
6,192✔
659
        AT.comsym[6] = 1;
6,192✔
660
        AT.comsym[7] = 3;
6,192✔
661
        AT.comnum[0] = 4;
6,192✔
662
        AT.comnum[1] = 1;
6,192✔
663
        AT.comnum[2] = 1;
6,192✔
664
        AT.comnum[3] = 3;
6,192✔
665
        AT.comfun[0] = FUNHEAD+4;
6,192✔
666
        AT.comfun[1] = FUNCTION;
6,192✔
667
        AT.comfun[2] = FUNHEAD;
6,192✔
668
        AT.comfun[3] = 0;
6,192✔
669
#if FUNHEAD > 3
670
        for ( i = 4; i <= FUNHEAD; i++ )
671
                AT.comfun[i] = 0;
672
#endif
673
        AT.comfun[FUNHEAD+1] = 1;
6,192✔
674
        AT.comfun[FUNHEAD+2] = 1;
6,192✔
675
        AT.comfun[FUNHEAD+3] = 3;
6,192✔
676
        AT.comind[0] = 7;
6,192✔
677
        AT.comind[1] = INDEX;
6,192✔
678
        AT.comind[2] = 3;
6,192✔
679
        AT.comind[3] = 0;
6,192✔
680
        AT.comind[4] = 1;
6,192✔
681
        AT.comind[5] = 1;
6,192✔
682
        AT.comind[6] = 3;
6,192✔
683
        AT.locwildvalue[0] = SUBEXPRESSION;
6,192✔
684
        AT.locwildvalue[1] = SUBEXPSIZE;
6,192✔
685
        for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
24,768✔
686
        AT.mulpat[0] = TYPEMULT;
6,192✔
687
        AT.mulpat[1] = SUBEXPSIZE+3;
6,192✔
688
        AT.mulpat[2] = 0;
6,192✔
689
        AT.mulpat[3] = SUBEXPRESSION;
6,192✔
690
        AT.mulpat[4] = SUBEXPSIZE;
6,192✔
691
        AT.mulpat[5] = 0;
6,192✔
692
        AT.mulpat[6] = 1;
6,192✔
693
        for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
24,768✔
694
        AT.proexp[0] = SUBEXPSIZE+4;
6,192✔
695
        AT.proexp[1] = EXPRESSION;
6,192✔
696
        AT.proexp[2] = SUBEXPSIZE;
6,192✔
697
        AT.proexp[3] = -1;
6,192✔
698
        AT.proexp[4] = 1;
6,192✔
699
        for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
12,384✔
700
        AT.proexp[SUBEXPSIZE+1] = 1;
6,192✔
701
        AT.proexp[SUBEXPSIZE+2] = 1;
6,192✔
702
        AT.proexp[SUBEXPSIZE+3] = 3;
6,192✔
703
        AT.proexp[SUBEXPSIZE+4] = 0;
6,192✔
704
        AT.dummysubexp[0] = SUBEXPRESSION;
6,192✔
705
        AT.dummysubexp[1] = SUBEXPSIZE+4;
6,192✔
706
        for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
24,768✔
707
        AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
6,192✔
708
        AT.dummysubexp[SUBEXPSIZE+1] = 4;
6,192✔
709
        AT.dummysubexp[SUBEXPSIZE+2] = 0;
6,192✔
710
        AT.dummysubexp[SUBEXPSIZE+3] = 0;
6,192✔
711

712
        AT.MinVecArg[0] = 7+ARGHEAD;
6,192✔
713
        AT.MinVecArg[ARGHEAD] = 7;
6,192✔
714
        AT.MinVecArg[1+ARGHEAD] = INDEX;
6,192✔
715
        AT.MinVecArg[2+ARGHEAD] = 3;
6,192✔
716
        AT.MinVecArg[3+ARGHEAD] = 0;
6,192✔
717
        AT.MinVecArg[4+ARGHEAD] = 1;
6,192✔
718
        AT.MinVecArg[5+ARGHEAD] = 1;
6,192✔
719
        AT.MinVecArg[6+ARGHEAD] = -3;
6,192✔
720
        t = AT.FunArg;
6,192✔
721
        *t++ = 4+ARGHEAD+FUNHEAD;
6,192✔
722
        for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
12,384✔
723
        *t++ = 4+FUNHEAD;
6,192✔
724
        *t++ = 0;
6,192✔
725
        *t++ = FUNHEAD;
6,192✔
726
        for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
12,384✔
727
        *t++ = 1; *t++ = 1; *t++ = 3;
6,192✔
728

729
        AT.inprimelist = -1;
6,192✔
730
        AT.sizeprimelist = 0;
6,192✔
731
        AT.primelist = 0;
6,192✔
732
        AT.nfac = AT.nBer = 0;
6,192✔
733
        AT.factorials = 0;
6,192✔
734
        AT.bernoullis = 0;
6,192✔
735
        AR.wranfia = 0;
6,192✔
736
        AR.wranfcall = 0;
6,192✔
737
        AR.wranfnpair1 = NPAIR1;
6,192✔
738
        AR.wranfnpair2 = NPAIR2;
6,192✔
739
        AR.wranfseed = 0;
6,192✔
740
        AN.SplitScratch = 0;
6,192✔
741
        AN.SplitScratchSize = AN.InScratch = 0;
6,192✔
742
        AN.SplitScratch1 = 0;
6,192✔
743
        AN.SplitScratchSize1 = AN.InScratch1 = 0;
6,192✔
744
/*
745
        Now the sort buffers. They depend on which thread. The master
746
        inherits the sortbuffer from AM.S0
747
*/
748
        if ( identity == 0 ) {
6,192✔
749
                AT.S0 = AM.S0;
1,560✔
750
        }
751
        else {
752
/*
753
                For the moment we don't have special settings.
754
                They may become costly in virtual memory.
755
*/
756
                AT.S0 = AllocSort(AM.S0->LargeSize*sizeof(WORD)/numberofworkers
4,632✔
757
                                                 ,AM.S0->SmallSize*sizeof(WORD)/numberofworkers
4,632✔
758
                                                 ,AM.S0->SmallEsize*sizeof(WORD)/numberofworkers
4,632✔
759
                                                 ,AM.S0->TermsInSmall
760
                                                 ,AM.S0->MaxPatches
761
/*                                                 ,AM.S0->MaxPatches/numberofworkers  */
762
                                                 ,AM.S0->MaxFpatches/numberofworkers
4,632✔
763
                                                 ,AM.S0->file.POsize
4,632✔
764
                                                 ,0);
765
        }
766
        AR.CompressPointer = AR.CompressBuffer;
6,192✔
767
/*
768
        Install the store caches (15-aug-2006 JV)
769
*/
770
        AT.StoreCache = AT.StoreCacheAlloc = 0;
6,192✔
771
        if ( AM.NumStoreCaches > 0 ) {
6,192✔
772
                STORECACHE sa, sb;
6,192✔
773
                LONG size;
6,192✔
774
                size = sizeof(struct StOrEcAcHe)+AM.SizeStoreCache;
6,192✔
775
                size = ((size-1)/sizeof(size_t)+1)*sizeof(size_t);
6,192✔
776
                AT.StoreCacheAlloc = (STORECACHE)Malloc1(size*AM.NumStoreCaches,"StoreCaches");
6,192✔
777
                sa = AT.StoreCache = AT.StoreCacheAlloc;
6,192✔
778
                for ( i = 0; i < AM.NumStoreCaches; i++ ) {
30,960✔
779
                        sb = (STORECACHE)(void *)((UBYTE *)sa+size);
24,768✔
780
                        if ( i == AM.NumStoreCaches-1 ) {
24,768✔
781
                                sa->next = 0;
6,192✔
782
                        }
783
                        else {
784
                                sa->next = sb;
18,576✔
785
                        }
786
                        SETBASEPOSITION(sa->position,-1);
24,768✔
787
                        SETBASEPOSITION(sa->toppos,-1);
24,768✔
788
                        sa = sb;
24,768✔
789
                }                
790
        }
791

792
        ReserveTempFiles(2);
6,192✔
793
        return(B);
6,192✔
794
OnError:;
×
795
        MLOCK(ErrorMessageLock);
×
796
        MesPrint("Error initializing thread %d",identity);
×
797
        MUNLOCK(ErrorMessageLock);
×
798
        Terminate(-1);
×
799
        return(B);
×
800
}
801

802
/*
803
          #] InitializeOneThread : 
804
          #[ FinalizeOneThread :
805
*/
806
/**
807
 *        To be called at the end of the run to give the final time statistics for
808
 *        this thread.
809
 *
810
 *        @param identity The TFORM defined integer identity of the thread.
811
 *                        In principle we could find it out from here with a call
812
 *                        to WhoAmI but because this is to be called at a very
813
 *                        late stage during clean up, we don't want to run any risks.
814
 */
815

816
void FinalizeOneThread(int identity)
5,408✔
817
{
818
        timerinfo[identity] = TimeCPU(1);
5,408✔
819
}
5,408✔
820

821
/*
822
          #] FinalizeOneThread : 
823
          #[ ClearAllThreads :
824
*/
825
/**
826
 *        To be called at the end of running TFORM.
827
 *        Theoretically the system can clean up after up, but it may be better
828
 *        to do it ourselves.
829
 */
830

831
void ClearAllThreads(void)
×
832
{
833
        int i;
×
834
        MasterWaitAll();
×
835
        for ( i = 1; i <= numberofworkers; i++ ) {
×
836
                WakeupThread(i,CLEARCLOCK);
×
837
        }
838
#ifdef WITHSORTBOTS
839
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
×
840
                WakeupThread(i,CLEARCLOCK);
×
841
        }
842
#endif
843
}
×
844

845
/*
846
          #] ClearAllThreads : 
847
          #[ TerminateAllThreads :
848
*/
849
/**
850
 *        To be called at the end of running TFORM.
851
 *        Theoretically the system can clean up after up, but it may be better
852
 *        to do it ourselves.
853
 */
854

855
void TerminateAllThreads(void)
1,368✔
856
{
857
        int i;
1,368✔
858
        for ( i = 1; i <= numberofworkers; i++ ) {
5,424✔
859
                GetThread(i);
4,056✔
860
                WakeupThread(i,TERMINATETHREAD);
4,056✔
861
        }
862
#ifdef WITHSORTBOTS
863
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
2,720✔
864
                WakeupThread(i,TERMINATETHREAD);
1,352✔
865
        }
866
#endif
867
        for ( i = 1; i <= numberofworkers; i++ ) {
5,424✔
868
                pthread_join(threadpointers[i],NULL);
4,056✔
869
        }
870
#ifdef WITHSORTBOTS
871
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
2,720✔
872
                pthread_join(threadpointers[i],NULL);
1,352✔
873
        }
874
#endif
875
}
1,368✔
876

877
/*
878
          #] TerminateAllThreads : 
879
          #[ MakeThreadBuckets :
880
*/
881
/**
882
 *        Creates 2*number thread buckets. We want double the number because
883
 *        we want to prepare number of them while another number are occupied.
884
 *
885
 *        Each bucket should have about AC.ThreadBucketSize*AM.MaxTerm words.
886
 *
887
 *        When loading a thread we only have to pass the address of a full bucket.
888
 *        This gives more overlap between the master and the workers and hence
889
 *        less waiting.
890
 *
891
 *        The buckets are used because sending terms one by one to the workers
892
 *        costs too much overhead. Hence we put a number of terms in each bucket
893
 *        and then pass the whole bucket. In the ideal case the master loads the
894
 *        buckets while the workers are processing the contents of the buckets
895
 *        they have been assigned. In practise often the processing can go faster
896
 *        than that the master can fill the buckets for all workers.
897
 *        It should be possible to improve this bucket system, but the trivial
898
 *        idea 
899
 *
900
 *        @param number The number of workers
901
 *        @param par    par = 0: First allocation
902
 *                      par = 1: Reallocation when we change the bucket size with the 
903
 *                               threadbucketsize statement.
904
 */
905

906
int MakeThreadBuckets(int number, int par)
1,560✔
907
{
908
        int i;
1,560✔
909
        LONG sizethreadbuckets;
1,560✔
910
        THREADBUCKET *thr;
1,560✔
911
/*
912
        First we need a decent estimate. Not all terms should be maximal.
913
        Note that AM.MaxTer is in bytes!!!
914
        Maybe we should try to limit the size here a bit more effectively.
915
        This is a great consumer of memory.
916
*/
917
        sizethreadbuckets = ( AC.ThreadBucketSize + 1 ) * AM.MaxTer + 2*sizeof(WORD);
1,560✔
918
        if ( AC.ThreadBucketSize >= 250 )      sizethreadbuckets /= 4;
1,560✔
919
        else if ( AC.ThreadBucketSize >= 90 )  sizethreadbuckets /= 3;
8✔
920
        else if ( AC.ThreadBucketSize >= 40 )  sizethreadbuckets /= 2;
8✔
921
        sizethreadbuckets /= sizeof(WORD);
1,560✔
922
        
923
        if ( par == 0 ) {
1,560✔
924
                numthreadbuckets = 2*(number-1);
1,560✔
925
                threadbuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
1,560✔
926
                freebuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
1,560✔
927
        }
928
        if ( par > 0 ) {
1,560✔
929
                if ( sizethreadbuckets <= threadbuckets[0]->threadbuffersize ) return(0);
×
930
                for ( i = 0; i < numthreadbuckets; i++ ) {
×
931
                        thr = threadbuckets[i];
×
932
                        M_free(thr->deferbuffer,"deferbuffer");
×
933
                }
934
        }
935
        else {
936
                for ( i = 0; i < numthreadbuckets; i++ ) {
10,824✔
937
                        threadbuckets[i] = (THREADBUCKET *)Malloc1(sizeof(THREADBUCKET),"threadbuckets");
9,264✔
938
                        threadbuckets[i]->lock = dummylock;
9,264✔
939
                }
940
        }
941
        for ( i = 0; i < numthreadbuckets; i++ ) {
10,824✔
942
                thr = threadbuckets[i];
9,264✔
943
                thr->threadbuffersize = sizethreadbuckets;
9,264✔
944
                thr->free = BUCKETFREE;
9,264✔
945
                thr->deferbuffer = (POSITION *)Malloc1(2*sizethreadbuckets*sizeof(WORD)
18,528✔
946
                                        +(AC.ThreadBucketSize+1)*sizeof(POSITION),"deferbuffer");
9,264✔
947
                thr->threadbuffer = (WORD *)(thr->deferbuffer+AC.ThreadBucketSize+1);
9,264✔
948
                thr->compressbuffer = (WORD *)(thr->threadbuffer+sizethreadbuckets);
9,264✔
949
                thr->busy = BUCKETPREPARINGTERM;
9,264✔
950
                thr->usenum = thr->totnum = 0;
9,264✔
951
                thr->type = BUCKETDOINGTERMS;
9,264✔
952
        }
953
        return(0);
954
}
955

956
/*
957
          #] MakeThreadBuckets : 
958
          #[ GetTimerInfo :
959
*/
960

961
/**
962
 *  Returns a pointer to the static timerinfo together with information about
963
 *  its size. This is used by the checkpoint code to save this information in
964
 *  the recovery file.
965
 */
966
int GetTimerInfo(LONG** ti,LONG** sti)
×
967
{
968
        *ti = timerinfo;
×
969
        *sti = sumtimerinfo;
×
970
#ifdef WITHSORTBOTS
971
        return AM.totalnumberofthreads*2;
×
972
#else
973
        return AM.totalnumberofthreads;
974
#endif
975
}
976

977
/*
978
          #] GetTimerInfo : 
979
          #[ WriteTimerInfo :
980
*/
981

982
/**
983
 *  Writes data into the static timerinfo variable. This is used by the
984
 *  checkpoint code to restore the correct timings for the individual threads.
985
 */
986
void WriteTimerInfo(LONG* ti,LONG* sti)
×
987
{
988
        int i;
×
989
#ifdef WITHSORTBOTS
990
        int max = AM.totalnumberofthreads*2;
×
991
#else
992
        int max = AM.totalnumberofthreads;
993
#endif
994
        for ( i=0; i<max; ++i ) {
×
995
                timerinfo[i] = ti[i];
×
996
                sumtimerinfo[i] = sti[i];
×
997
        }
998
}
×
999

1000
/*
1001
          #] WriteTimerInfo : 
1002
          #[ GetWorkerTimes :
1003
*/
1004
/**
1005
 *        Gets the total CPU time of all workers together.
1006
 *        To be called at the end of the TFORM run.
1007
 */
1008

1009
LONG GetWorkerTimes(void)
3,408✔
1010
{
1011
        LONG retval = 0;
3,408✔
1012
        int i;
3,408✔
1013
        for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
13,560✔
1014
#ifdef WITHSORTBOTS
1015
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ )
6,792✔
1016
                retval += timerinfo[i] + sumtimerinfo[i];
3,384✔
1017
#endif
1018
        return(retval);
3,408✔
1019
}
1020

1021
/*
1022
          #] GetWorkerTimes : 
1023
          #[ UpdateOneThread :
1024
*/
1025
/**
1026
 *        Fix up some of the things that happened at compiler time.
1027
 *
1028
 *        @param identity The TFORM defined integer thread identifier.
1029
 */
1030

1031
int UpdateOneThread(int identity)
20,244✔
1032
{
1033
        ALLPRIVATES *B = AB[identity], *B0 = AB[0];
20,244✔
1034
        AR.GetFile = AR0.GetFile;
20,244✔
1035
        AR.KeptInHold = AR0.KeptInHold;
20,244✔
1036
        AR.CurExpr = AR0.CurExpr;
20,244✔
1037
        AR.SortType = AC.SortType;
20,244✔
1038
        if ( AT.WildcardBufferSize < AC.WildcardBufferSize ) {
20,244✔
1039
                M_free(AT.WildArgTaken,"argument list names");
×
1040
                AT.WildcardBufferSize = AC.WildcardBufferSize;
×
1041
                AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
×
1042
                                ,"argument list names");
1043
                if ( AT.WildArgTaken == 0 ) return(-1);
×
1044
        }
1045
        return(0);
1046
}
1047

1048
/*
1049
          #] UpdateOneThread : 
1050
          #[ LoadOneThread :
1051
*/
1052
/**
1053
 *        Loads all relevant variables from thread 'from' into thread 'identity'
1054
 *        This is to be done just prior to waking up the thread.
1055
 *        It is important to keep the number of variables to be copied to a minimum
1056
 *        because this is part of the 'overhead'.
1057
 *
1058
 *        @param from     the source thread which has all the variables already
1059
 *        @param identity the TFORM defined integer thread identifier of the thread that needs the copy
1060
 *        @param thr      the bucket that contains the terms to be processed by 'identity'
1061
 *        @param par                if 1 copies the already active pieces in the (de)compress buffer
1062
 *        @return Standard return convention (OK -> 0)
1063
 */
1064

1065
int LoadOneThread(int from, int identity, THREADBUCKET *thr, int par)
199,682✔
1066
{
1067
        WORD *t1, *t2;
199,682✔
1068
        ALLPRIVATES *B = AB[identity], *B0 = AB[from];
199,682✔
1069

1070
        AR.DefPosition = AR0.DefPosition;
199,682✔
1071
        AR.NoCompress = AR0.NoCompress;
199,682✔
1072
        AR.gzipCompress = AR0.gzipCompress;
199,682✔
1073
        AR.BracketOn = AR0.BracketOn;
199,682✔
1074
        AR.CurDum = AR0.CurDum;
199,682✔
1075
        AR.DeferFlag = AR0.DeferFlag;
199,682✔
1076
        AR.TePos = 0;
199,682✔
1077
        AR.sLevel = AR0.sLevel;
199,682✔
1078
        AR.Stage4Name = AR0.Stage4Name;
199,682✔
1079
        AR.GetOneFile = AR0.GetOneFile;
199,682✔
1080
        AR.PolyFun = AR0.PolyFun;
199,682✔
1081
        AR.PolyFunInv = AR0.PolyFunInv;
199,682✔
1082
        AR.PolyFunType = AR0.PolyFunType;
199,682✔
1083
        AR.PolyFunExp = AR0.PolyFunExp;
199,682✔
1084
        AR.PolyFunVar = AR0.PolyFunVar;
199,682✔
1085
        AR.PolyFunPow = AR0.PolyFunPow;
199,682✔
1086
        AR.Eside = AR0.Eside;
199,682✔
1087
        AR.Cnumlhs = AR0.Cnumlhs;
199,682✔
1088
/*
1089
        AR.MaxBracket = AR0.MaxBracket;
1090

1091
        The compressbuffer contents are mainly relevant for keep brackets
1092
        We should do this only if there is a keep brackets statement
1093
        We may however still need the compressbuffer for expressions in the rhs.
1094
*/
1095
        if ( par >= 1 ) {
199,682✔
1096
/*
1097
                We may not need this %%%%% 7-apr-2006
1098
*/
1099
                t1 = AR.CompressBuffer; t2 = AR0.CompressBuffer;
×
1100
                while ( t2 < AR0.CompressPointer ) *t1++ = *t2++;
×
1101
                AR.CompressPointer = t1;
×
1102

1103
        }
1104
        else {
1105
                AR.CompressPointer = AR.CompressBuffer;
199,682✔
1106
        }
1107
        if ( AR.DeferFlag ) {
199,682✔
1108
                if ( AR.infile->handle < 0 ) {
2,460✔
1109
                        AR.infile->POfill = AR0.infile->POfill;
2,343✔
1110
                }
1111
                else {
1112
/*
1113
                        We have to set the value of POposition to something that will
1114
                        force a read in the first try.
1115
*/
1116
                        AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer;
117✔
1117
                }
1118
        }
1119
        if ( par == 0 ) {
199,682✔
1120
                AN.threadbuck = thr;
23,598✔
1121
                AN.ninterms = thr->firstterm;
23,598✔
1122
        }
1123
        else if ( par == 1 ) {
176,084✔
1124
                WORD *tstop;
×
1125
                t1 = thr->threadbuffer; tstop = t1 + *t1;
×
1126
                t2 = AT.WorkPointer;
×
1127
                while ( t1 < tstop ) *t2++ = *t1++;
×
1128
                AN.ninterms = thr->firstterm;
×
1129
        }
1130
        AN.TeInFun = 0;
199,682✔
1131
        AN.ncmod = AC.ncmod;
199,682✔
1132
        AT.BrackBuf = AT0.BrackBuf;
199,682✔
1133
        AT.bracketindexflag = AT0.bracketindexflag;
199,682✔
1134
        AN.PolyFunTodo = 0;
199,682✔
1135
/*
1136
        The relevant variables and the term are in their place.
1137
        There is nothing more to do.
1138
*/
1139
        return(0);
199,682✔
1140
}
1141

1142
/*
1143
          #] LoadOneThread : 
1144
          #[ BalanceRunThread :
1145
*/
1146
/**
1147
 *        To start a thread from the Generator routine we need to pass a number
1148
 *        of variables.
1149
 *        This is part of the second stage load balancing. The second stage is
1150
 *        when we interfere with the expansion tree in Generator and let branches
1151
 *        of the tree be treated by other workers.
1152
 *        Early experiments show disappointing results and hence the system is
1153
 *        currently disabled.
1154
 *
1155
 *        @param identity  The identity of the thread that will receive the term.
1156
 *        @param term      The term to be passed to thread 'identity'
1157
 *        @param level     The level at which we are in the tree. Defines the statement.
1158
 *        @return Standard return convention (OK -> 0)
1159
 */
1160

1161
int BalanceRunThread(PHEAD int identity, WORD *term, WORD level)
×
1162
{
1163
        GETBIDENTITY
1164
        ALLPRIVATES *BB;
×
1165
        WORD *t, *tt;
×
1166
        int i, *ti, *tti;
×
1167

1168
        LoadOneThread(AT.identity,identity,0,2);
×
1169
/*
1170
        Extra loading if needed. Quantities changed in Generator.
1171
        Like the level that has to be passed.
1172
*/
1173
        BB = AB[identity];
×
1174
        BB->R.level = level;
×
1175
        BB->T.TMbuff = AT.TMbuff;
×
1176
        ti = AT.RepCount; tti = BB->T.RepCount;
×
1177
        i = AN.RepPoint - AT.RepCount;
×
1178
        BB->N.RepPoint = BB->T.RepCount + i;
×
1179
        for ( ; i >= 0; i-- ) tti[i] = ti[i];
×
1180

1181
        t = term; i = *term;
×
1182
        tt = BB->T.WorkSpace;
×
1183
        NCOPY(tt,t,i);
×
1184
        BB->T.WorkPointer = tt;
×
1185

1186
        WakeupThread(identity,HIGHERLEVELGENERATION);
×
1187

1188
        return(0);
×
1189
}
1190

1191
/*
1192
          #] BalanceRunThread : 
1193
          #[ SetWorkerFiles :
1194
*/
1195
/**
1196
 *        Initializes the scratch files at the start of the execution of a module.
1197
 */
1198

1199
void SetWorkerFiles(void)
7,144✔
1200
{
1201
        int id;
7,144✔
1202
        ALLPRIVATES *B, *B0 = AB[0];
7,144✔
1203
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
28,576✔
1204
                B = AB[id];
21,432✔
1205
                AR.infile = &(AR.Fscr[0]);
21,432✔
1206
                AR.outfile = &(AR.Fscr[1]);
21,432✔
1207
                AR.hidefile = &(AR.Fscr[2]);
21,432✔
1208
                AR.infile->handle = AR0.infile->handle;
21,432✔
1209
                AR.hidefile->handle = AR0.hidefile->handle;
21,432✔
1210
                if ( AR.infile->handle < 0 ) {
21,432✔
1211
                        AR.infile->PObuffer = AR0.infile->PObuffer;
21,360✔
1212
                        AR.infile->POstop = AR0.infile->POstop;
21,360✔
1213
                        AR.infile->POfill = AR0.infile->POfill;
21,360✔
1214
                        AR.infile->POfull = AR0.infile->POfull;
21,360✔
1215
                        AR.infile->POsize = AR0.infile->POsize;
21,360✔
1216
                        AR.InInBuf = AR0.InInBuf;
21,360✔
1217
                        AR.infile->POposition = AR0.infile->POposition;
21,360✔
1218
                        AR.infile->filesize = AR0.infile->filesize;
21,360✔
1219
                }
1220
                else {
1221
                        AR.infile->PObuffer = AR.infile->wPObuffer;
72✔
1222
                        AR.infile->POstop = AR.infile->wPOstop;
72✔
1223
                        AR.infile->POfill = AR.infile->wPOfill;
72✔
1224
                        AR.infile->POfull = AR.infile->wPOfull;
72✔
1225
                        AR.infile->POsize = AR.infile->wPOsize;
72✔
1226
                        AR.InInBuf = 0;
72✔
1227
                        PUTZERO(AR.infile->POposition);
72✔
1228
                }
1229
/*
1230
                If there is some writing, it betters happens to ones own outfile.
1231
                Currently this is to be done only for InParallel.
1232
                Merging of the outputs is then done by the CopyExpression routine.
1233
*/
1234
                {
1235
                        AR.outfile->PObuffer = AR.outfile->wPObuffer;
21,432✔
1236
                        AR.outfile->POstop = AR.outfile->wPOstop;
21,432✔
1237
                        AR.outfile->POfill = AR.outfile->wPOfill;
21,432✔
1238
                        AR.outfile->POfull = AR.outfile->wPOfull;
21,432✔
1239
                        AR.outfile->POsize = AR.outfile->wPOsize;
21,432✔
1240
                        PUTZERO(AR.outfile->POposition);
21,432✔
1241
                }
1242
                if ( AR.hidefile->handle < 0 ) {
21,432✔
1243
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
21,432✔
1244
                        AR.hidefile->POstop = AR0.hidefile->POstop;
21,432✔
1245
                        AR.hidefile->POfill = AR0.hidefile->POfill;
21,432✔
1246
                        AR.hidefile->POfull = AR0.hidefile->POfull;
21,432✔
1247
                        AR.hidefile->POsize = AR0.hidefile->POsize;
21,432✔
1248
                        AR.InHiBuf = AR0.InHiBuf;
21,432✔
1249
                        AR.hidefile->POposition = AR0.hidefile->POposition;
21,432✔
1250
                        AR.hidefile->filesize = AR0.hidefile->filesize;
21,432✔
1251
                }
1252
                else {
1253
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
1254
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
1255
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
1256
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
1257
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
1258
                        AR.InHiBuf = 0;
×
1259
                        PUTZERO(AR.hidefile->POposition);
×
1260
                }
1261
        }
1262
        if ( AR0.StoreData.dirtyflag ) {
7,144✔
1263
                for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
×
1264
                        B = AB[id];
×
1265
                        AR.StoreData = AR0.StoreData;
×
1266
                }
1267
        }
1268
}
7,144✔
1269

1270
/*
1271
          #] SetWorkerFiles : 
1272
          #[ RunThread :
1273
*/
1274
/**
1275
 *        This is the routine that represents each worker.
1276
 *        The model is that the worker waits for a 'signal'.
1277
 *        If there is a signal it wakes up, looks at what signal and then takes
1278
 *        the corresponding action. After this it goes back to sleep.
1279
 */
1280

1281
void *RunThread(void *dummy)
4,632✔
1282
{
1283
        WORD *term, *ttin, *tt, *ttco, *oldwork;
4,632✔
1284
        int identity, wakeupsignal, identityretv, i, tobereleased, errorcode;
4,632✔
1285
        ALLPRIVATES *B;
4,632✔
1286
        THREADBUCKET *thr;
4,632✔
1287
        POSITION *ppdef;
4,632✔
1288
        EXPRESSIONS e;
4,632✔
1289
        DUMMYUSE(dummy);
4,632✔
1290
        identity = SetIdentity(&identityretv);
4,632✔
1291
        threadpointers[identity] = pthread_self();
4,632✔
1292
        B = InitializeOneThread(identity);
4,632✔
1293
        while ( ( wakeupsignal = ThreadWait(identity) ) > 0 ) {
264,338✔
1294
                switch ( wakeupsignal ) {
259,842✔
1295
/*
1296
                        #[ STARTNEWEXPRESSION :
1297
*/
1298
                        case STARTNEWEXPRESSION:
20,244✔
1299
/*
1300
                                Set up the sort routines etc.
1301
                                Start with getting some buffers synchronized with the compiler
1302
*/
1303
                                if ( UpdateOneThread(identity) ) {
20,244✔
1304
                                        MLOCK(ErrorMessageLock);
×
1305
                                        MesPrint("Update error in starting expression in thread %d in module %d",identity,AC.CModule);
×
1306
                                        MUNLOCK(ErrorMessageLock);
×
1307
                                        Terminate(-1);
×
1308
                                }
1309
                                AR.DeferFlag = AC.ComDefer;
20,244✔
1310
                                AR.sLevel = AS.sLevel;
20,244✔
1311
                                AR.MaxDum = AM.IndDum;
20,244✔
1312
                                AR.expchanged = AB[0]->R.expchanged;
20,244✔
1313
                                AR.expflags = AB[0]->R.expflags;
20,244✔
1314
                                AR.PolyFun = AB[0]->R.PolyFun;
20,244✔
1315
                                AR.PolyFunInv = AB[0]->R.PolyFunInv;
20,244✔
1316
                                AR.PolyFunType = AB[0]->R.PolyFunType;
20,244✔
1317
                                AR.PolyFunExp = AB[0]->R.PolyFunExp;
20,244✔
1318
                                AR.PolyFunVar = AB[0]->R.PolyFunVar;
20,244✔
1319
                                AR.PolyFunPow = AB[0]->R.PolyFunPow;
20,244✔
1320
/*
1321
                                Now fire up the sort buffer.
1322
*/
1323
                                NewSort(BHEAD0);
20,244✔
1324
                                break;
20,244✔
1325
/*
1326
                        #] STARTNEWEXPRESSION : 
1327
                        #[ LOWESTLEVELGENERATION :
1328
*/
1329
                        case LOWESTLEVELGENERATION:
23,474✔
1330
#ifdef INNERTEST
1331
                                if ( AC.InnerTest ) {
1332
                                        if ( StrCmp(AC.TestValue,(UBYTE *)INNERTEST) == 0 ) {
1333
                                                MesPrint("Testing(Worker%d): value = %s",AT.identity,AC.TestValue);
1334
                                        }
1335
                                }
1336
#endif
1337
                                e = Expressions + AR.CurExpr;
23,474✔
1338
                                thr = AN.threadbuck;
23,474✔
1339
                                ppdef = thr->deferbuffer;
23,474✔
1340
                                ttin = thr->threadbuffer;
23,474✔
1341
                                ttco = thr->compressbuffer;
23,474✔
1342
                                term = AT.WorkPointer;
23,474✔
1343
                                thr->usenum = 0;
23,474✔
1344
                                tobereleased = 0;
23,474✔
1345
                                AN.inputnumber = thr->firstterm;
23,474✔
1346
                                AN.ninterms = thr->firstterm;
23,474✔
1347
                                do {
714,230✔
1348
                                  thr->usenum++;        /* For if the master wants to steal the bucket */
714,230✔
1349
                                  tt = term; i = *ttin;
714,230✔
1350
                                  NCOPY(tt,ttin,i);
30,324,930✔
1351
                                  AT.WorkPointer = tt;
714,230✔
1352
                                  if ( AR.DeferFlag ) {
714,230✔
1353
                                        tt = AR.CompressBuffer; i = *ttco;
2,768✔
1354
                                        NCOPY(tt,ttco,i);
71,384✔
1355
                                        AR.CompressPointer = tt;
2,768✔
1356
                                        AR.DefPosition = ppdef[0]; ppdef++;
2,768✔
1357
                                  }
1358
                                  if ( thr->free == BUCKETTERMINATED ) {
714,230✔
1359
/*
1360
                                    The next statement allows the master to steal the bucket
1361
                                    for load balancing purposes. We do still execute the current
1362
                                        term, but afterwards we drop out.
1363
                                        Once we have written the release code, we cannot use this
1364
                                        bucket anymore. Hence the exit to the label bucketstolen.
1365
*/
1366
                                        if ( thr->usenum == thr->totnum ) {
×
1367
                                                thr->free = BUCKETCOMINGFREE;
×
1368
                                        }
1369
                                        else {
1370
                                                thr->free = BUCKETRELEASED;
×
1371
                                                tobereleased = 1;
×
1372
                                        }
1373
                                  }
1374
/*
1375
                                        What if we want to steal and we set thr->free while
1376
                                        the thread is inside the next code for a long time?
1377
                                  if ( AT.LoadBalancing ) {
1378
*/
1379
                                        LOCK(thr->lock);
714,230✔
1380
                                        thr->busy = BUCKETDOINGTERM;
714,230✔
1381
                                        UNLOCK(thr->lock);
714,230✔
1382
/*
1383
                                  }
1384
                                  else {
1385
                                        thr->busy = BUCKETDOINGTERM;
1386
                                  }
1387
*/
1388
                                  AN.RepPoint = AT.RepCount + 1;
714,230✔
1389

1390
                                  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
714,230✔
1391
                                    StoreTerm(BHEAD term);
×
1392
                                  }
1393
                                  else {
1394
                                  if ( AR.DeferFlag ) {
714,230✔
1395
                                        AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
2,768✔
1396
                                  }
1397
                                  else {
1398
                                        AN.IndDum = AM.IndDum;
711,462✔
1399
                                        AR.CurDum = ReNumber(BHEAD term);
711,462✔
1400
                                  }
1401
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
714,230✔
1402
                                  if ( AN.ncmod ) {
714,230✔
1403
                                        if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
4✔
1404
                                        else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
4✔
1405
                                  }
1406
                                  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
714,226✔
1407
                                  if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
714,230✔
1408
                                        MLOCK(ErrorMessageLock);
×
1409
                                        MesPrint("Thread %w executing term:");
×
1410
                                        PrintTerm(term,"LLG");
×
1411
                                        MUNLOCK(ErrorMessageLock);
×
1412
                                  }
1413
                                  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
714,230✔
1414
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
4,552✔
1415
                                                PolyFunClean(BHEAD term);
4,552✔
1416
                                  }
1417
                                  if ( Generator(BHEAD term,0) ) {
714,230✔
1418
                                        LowerSortLevel();
8✔
1419
                                        MLOCK(ErrorMessageLock);
8✔
1420
                                        MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
8✔
1421
                                        MUNLOCK(ErrorMessageLock);
8✔
1422
                                        Terminate(-1);
8✔
1423
                                  }
1424
                                  AN.ninterms++;
714,106✔
1425
                                  }
1426
/*                                  if ( AT.LoadBalancing ) { */
1427
                                        LOCK(thr->lock);
714,106✔
1428
                                        thr->busy = BUCKETPREPARINGTERM;
714,106✔
1429
                                        UNLOCK(thr->lock);
714,106✔
1430
/*
1431
                                  }
1432
                                  else {
1433
                                        thr->busy = BUCKETPREPARINGTERM;
1434
                                  }
1435
*/
1436
                                  if ( thr->free == BUCKETTERMINATED ) {
714,106✔
1437
                                        if ( thr->usenum == thr->totnum ) {
204✔
1438
                                                thr->free = BUCKETCOMINGFREE;
×
1439
                                        }
1440
                                        else {
1441
                                                thr->free = BUCKETRELEASED;
204✔
1442
                                                tobereleased = 1;
204✔
1443
                                        }
1444
                                  }
1445
                                  if ( tobereleased ) goto bucketstolen;
714,106✔
1446
                                } while ( *ttin );
713,902✔
1447
                                thr->free = BUCKETCOMINGFREE;
23,146✔
1448
bucketstolen:;
23,350✔
1449
/*                                if ( AT.LoadBalancing ) { */
1450
                                        LOCK(thr->lock);
23,350✔
1451
                                        thr->busy = BUCKETTOBERELEASED;
23,350✔
1452
                                        UNLOCK(thr->lock);
23,350✔
1453
/*                                }
1454
                                else {
1455
                                        thr->busy = BUCKETTOBERELEASED;
1456
                                }
1457
*/
1458
                                AT.WorkPointer = term;
23,350✔
1459
                                break;
23,350✔
1460
/*
1461
                        #] LOWESTLEVELGENERATION : 
1462
                        #[ FINISHEXPRESSION :
1463
*/
1464
#ifdef WITHSORTBOTS
1465
                        case CLAIMOUTPUT:
×
1466
                                LOCK(AT.SB.MasterBlockLock[1]);
×
1467
                                break;
×
1468
#endif
1469
                        case FINISHEXPRESSION:
19,872✔
1470
/*
1471
                                Finish the sort
1472

1473
                                Start with claiming the first block
1474
                                Once we have claimed it we can let the master know that
1475
                                everything is all right.
1476
*/
1477
                                LOCK(AT.SB.MasterBlockLock[1]);
19,872✔
1478
                                ThreadClaimedBlock(identity);
19,872✔
1479
/*
1480
                                Entry for when we work with sortbots
1481
*/
1482
#ifdef WITHSORTBOTS
1483
                                /* fall through */
1484
                        case FINISHEXPRESSION2:
19,872✔
1485
#endif
1486
/*
1487
                                Now we may need here an fsync on the sort file
1488
*/
1489
                                if ( AC.ThreadSortFileSynch ) {
19,872✔
1490
                                  if ( AT.S0->file.handle >= 0 ) {
×
1491
                                        SynchFile(AT.S0->file.handle);
×
1492
                                  }
1493
                                }
1494
                                AT.SB.FillBlock = 1;
19,872✔
1495
                                AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
19,872✔
1496
                                errorcode = EndSort(BHEAD AT.S0->sBuffer,0);
19,872✔
1497
                                UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
19,860✔
1498
                                UpdateMaxSize();
19,860✔
1499
                                if ( errorcode ) {
19,860✔
1500
                                        MLOCK(ErrorMessageLock);
×
1501
                                        MesPrint("Error terminating sort in thread %d in module %d",identity,AC.CModule);
×
1502
                                        MUNLOCK(ErrorMessageLock);
×
1503
                                        Terminate(-1);
×
1504
                                }
1505
                                break;
1506
/*
1507
                        #] FINISHEXPRESSION : 
1508
                        #[ CLEANUPEXPRESSION :
1509
*/
1510
                        case CLEANUPEXPRESSION:
19,860✔
1511
/*
1512
                                Cleanup everything and wait for the next expression
1513
*/
1514
                                if ( AR.outfile->handle >= 0 ) {
19,860✔
1515
                                        CloseFile(AR.outfile->handle);
×
1516
                                        AR.outfile->handle = -1;
×
1517
                                        remove(AR.outfile->name);
×
1518
                                        AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
×
1519
                                        PUTZERO(AR.outfile->POposition);
×
1520
                                        PUTZERO(AR.outfile->filesize);
×
1521
                                }
1522
                                else {
1523
                                        AR.outfile->POfill = AR.outfile->POfull = AR.outfile->PObuffer;
19,860✔
1524
                                        PUTZERO(AR.outfile->POposition);
19,860✔
1525
                                        PUTZERO(AR.outfile->filesize);
19,860✔
1526
                                }
1527
                                {
1528
                                        CBUF *C = cbuf+AT.ebufnum;
19,860✔
1529
                                        WORD **w, ii;
19,860✔
1530
                                        if ( C->numrhs > 0 || C->numlhs > 0 ) {
19,860✔
1531
                                                if ( C->rhs ) {
×
1532
                                                        w = C->rhs; ii = C->numrhs;
1533
                                                        do { *w++ = 0; } while ( --ii > 0 );
×
1534
                                                }
1535
                                                if ( C->lhs ) {
×
1536
                                                        w = C->lhs; ii = C->numlhs;
×
1537
                                                        do { *w++ = 0; } while ( --ii > 0 );
×
1538
                                                }
1539
                                                C->numlhs = C->numrhs = 0;
×
1540
                                                ClearTree(AT.ebufnum);
×
1541
                                                C->Pointer = C->Buffer;
×
1542
                                        }
1543
                                }
1544
                                break;
1545
/*
1546
                        #] CLEANUPEXPRESSION : 
1547
                        #[ HIGHERLEVELGENERATION :
1548
*/
1549
                        case HIGHERLEVELGENERATION:
×
1550
/*
1551
                                When foliating halfway the tree.
1552
                                This should only be needed in a second level load balancing
1553
*/
1554
                                term = AT.WorkSpace; AT.WorkPointer = term + *term;
×
1555
                                if ( Generator(BHEAD term,AR.level) ) {
×
1556
                                        LowerSortLevel();
×
1557
                                        MLOCK(ErrorMessageLock);
×
1558
                                        MesPrint("Error in load balancing one term at level %d in thread %d in module %d",AR.level,AT.identity,AC.CModule);
×
1559
                                        MUNLOCK(ErrorMessageLock);
×
1560
                                        Terminate(-1);
×
1561
                                }
1562
                                AT.WorkPointer = term;
×
1563
                                break;
×
1564
/*
1565
                        #] HIGHERLEVELGENERATION : 
1566
                        #[ STARTNEWMODULE :
1567
*/
1568
                        case STARTNEWMODULE:
×
1569
/*
1570
                                For resetting variables.
1571
*/
1572
                                SpecialCleanup(B);
×
1573
                                break;
×
1574
/*
1575
                        #] STARTNEWMODULE : 
1576
                        #[ TERMINATETHREAD :
1577
*/
1578
                        case TERMINATETHREAD:
×
1579
                                goto EndOfThread;
×
1580
/*
1581
                        #] TERMINATETHREAD : 
1582
                        #[ DOONEEXPRESSION :
1583

1584
                                When a thread has to do a complete (not too big) expression.
1585
                                The number of the expression to be done is in AR.exprtodo.
1586
                                The code is mostly taken from Processor. The only difference
1587
                                is with what to do with the output.
1588
                                The output should go to the scratch buffer of the worker
1589
                                (which is free at the right moment). If this buffer is too
1590
                                small we have a problem. We could write to file or give the
1591
                                master what we have and from now on the master has to collect
1592
                                pieces until things are complete.
1593
                                Note: this assumes that the expressions don't keep their order.
1594
                                If they have to keep their order, don't use this feature.
1595
*/
1596
                        case DOONEEXPRESSION: {
176,084✔
1597

1598
                                POSITION position, outposition;
176,084✔
1599
                                FILEHANDLE *fi, *fout, *oldoutfile;
176,084✔
1600
                                LONG dd = 0;
176,084✔
1601
                                WORD oldBracketOn = AR.BracketOn;
176,084✔
1602
                                WORD *oldBrackBuf = AT.BrackBuf;
176,084✔
1603
                                WORD oldbracketindexflag = AT.bracketindexflag;
176,084✔
1604
                                WORD fromspectator = 0;
176,084✔
1605
                                e = Expressions + AR.exprtodo;
176,084✔
1606
                                i = AR.exprtodo;
176,084✔
1607
                                AR.CurExpr = i;
176,084✔
1608
                                AR.SortType = AC.SortType;
176,084✔
1609
                                AR.expchanged = 0;
176,084✔
1610
                                if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
176,084✔
1611
                                        AR.BracketOn = 1;
×
1612
                                        AT.BrackBuf = AM.BracketFactors;
×
1613
                                        AT.bracketindexflag = 1;
×
1614
                                }
1615

1616
                                position = AS.OldOnFile[i];
176,084✔
1617
                                if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION ) {
176,084✔
1618
                                        AR.GetFile = 2; fi = AR.hidefile;
×
1619
                                }
1620
                                else {
1621
                                        AR.GetFile = 0; fi = AR.infile;
176,084✔
1622
                                }
1623
/*
1624
                                PUTZERO(fi->POposition);
1625
                                if ( fi->handle >= 0 ) {
1626
                                        fi->POfill = fi->POfull = fi->PObuffer;
1627
                                }
1628
*/
1629
                                SetScratch(fi,&position);
176,084✔
1630
                                term = oldwork = AT.WorkPointer;
176,084✔
1631
                                AR.CompressPointer = AR.CompressBuffer;
176,084✔
1632
                                AR.CompressPointer[0] = 0;
176,084✔
1633
                                AR.KeptInHold = 0;
176,084✔
1634
                                if ( GetTerm(BHEAD term) <= 0 ) {
176,084✔
1635
                                        MLOCK(ErrorMessageLock);
×
1636
                                        MesPrint("Expression %d has problems in scratchfile (t)",i);
×
1637
                                        MUNLOCK(ErrorMessageLock);
×
1638
                                        Terminate(-1);
×
1639
                                }
1640
                                if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
176,084✔
1641
                                term[3] = i;
176,084✔
1642
                                if ( term[5] < 0 ) {
176,084✔
1643
                                        fromspectator = -term[5];
×
1644
                                        PUTZERO(AM.SpectatorFiles[fromspectator-1].readpos);
×
1645
                                        term[5] = AC.cbufnum;
×
1646
                                }
1647
                                PUTZERO(outposition);
176,084✔
1648
                                fout = AR.outfile;
176,084✔
1649
                                fout->POfill = fout->POfull = fout->PObuffer;
176,084✔
1650
                                fout->POposition = outposition;
176,084✔
1651
                                if ( fout->handle >= 0 ) {
176,084✔
1652
                                        fout->POposition = outposition;
×
1653
                                }
1654
/*
1655
                                The next statement is needed because we need the system
1656
                                to believe that the expression is at position zero for
1657
                                the moment. In this worker, with no memory of other expressions,
1658
                                it is. This is needed for when a bracket index is made
1659
                                because there e->onfile is an offset. Afterwards, when the
1660
                                expression is written to its final location in the masters
1661
                                output e->onfile will get its real value.
1662
*/
1663
                                PUTZERO(e->onfile);
176,084✔
1664
                                if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) goto ProcErr;
176,084✔
1665

1666
                                AR.DeferFlag = AC.ComDefer;
176,084✔
1667

1668
                                AR.sLevel = AB[0]->R.sLevel;
176,084✔
1669
                                term = AT.WorkPointer;
176,084✔
1670
                                NewSort(BHEAD0);
176,084✔
1671
                                AR.MaxDum = AM.IndDum;
176,084✔
1672
                                AN.ninterms = 0;
176,084✔
1673
                                if ( fromspectator ) {
176,084✔
1674
                                 while ( GetFromSpectator(term,fromspectator-1) ) {
×
1675
                                  AT.WorkPointer = term + *term;
×
1676
                                  AN.RepPoint = AT.RepCount + 1;
×
1677
                                  AN.IndDum = AM.IndDum;
×
1678
                                  AR.CurDum = ReNumber(BHEAD term);
×
1679
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
×
1680
                                  if ( AN.ncmod ) {
×
1681
                                        if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
×
1682
                                        else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
×
1683
                                  }
1684
                                  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
×
1685
                                  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
×
1686
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
×
1687
                                                PolyFunClean(BHEAD term);
×
1688
                                  }
1689
                                  if ( Generator(BHEAD term,0) ) {
×
1690
                                        LowerSortLevel(); goto ProcErr;
×
1691
                                  }
1692
                                 }
1693
                                }
1694
                                else {
1695
                                 while ( GetTerm(BHEAD term) ) {
352,168✔
1696
                                  SeekScratch(fi,&position);
176,084✔
1697
                                  AN.ninterms++; dd = AN.deferskipped;
176,084✔
1698
                                  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
176,084✔
1699
                                          StoreTerm(BHEAD term);
×
1700
                                  }
1701
                                  else {
1702
                                  if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
176,084✔
1703
                                        if ( GetMoreTerms(term) < 0 ) {
×
1704
                                          LowerSortLevel(); goto ProcErr;
×
1705
                                        }
1706
                                    SeekScratch(fi,&position);
×
1707
                                  }
1708
                                  AT.WorkPointer = term + *term;
176,084✔
1709
                                  AN.RepPoint = AT.RepCount + 1;
176,084✔
1710
                                  if ( AR.DeferFlag ) {
176,084✔
1711
                                        AR.CurDum = AN.IndDum = Expressions[AR.exprtodo].numdummies;
×
1712
                                  }
1713
                                  else {
1714
                                        AN.IndDum = AM.IndDum;
176,084✔
1715
                                        AR.CurDum = ReNumber(BHEAD term);
176,084✔
1716
                                  }
1717
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
176,084✔
1718
                                  if ( AN.ncmod ) {
176,084✔
1719
                                        if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
×
1720
                                        else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
×
1721
                                  }
1722
                                  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
176,084✔
1723
                                  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
176,084✔
1724
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
×
1725
                                                PolyFunClean(BHEAD term);
×
1726
                                  }
1727
                                  if ( Generator(BHEAD term,0) ) {
176,084✔
1728
                                        LowerSortLevel(); goto ProcErr;
×
1729
                                  }
1730
                                  AN.ninterms += dd;
176,084✔
1731
                                  }
1732
                                  SetScratch(fi,&position);
176,084✔
1733
                                  if ( fi == AR.hidefile ) {
176,084✔
1734
                                        AR.InHiBuf = (fi->POfull-fi->PObuffer)
×
1735
                                                -DIFBASE(position,fi->POposition)/sizeof(WORD);
×
1736
                                  }
1737
                                  else {
1738
                                        AR.InInBuf = (fi->POfull-fi->PObuffer)
176,084✔
1739
                                                -DIFBASE(position,fi->POposition)/sizeof(WORD);
176,084✔
1740
                                  }
1741
                                 }
1742
                                }
1743
                                AN.ninterms += dd;
176,084✔
1744
                                if ( EndSort(BHEAD AT.S0->sBuffer,0) < 0 ) goto ProcErr;
176,084✔
1745
                                e->numdummies = AR.MaxDum - AM.IndDum;
176,084✔
1746
                                AR.BracketOn = oldBracketOn;
176,084✔
1747
                                AT.BrackBuf = oldBrackBuf;
176,084✔
1748
                                if ( ( e->vflags & TOBEFACTORED ) != 0 )
176,084✔
1749
                                                poly_factorize_expression(e);
×
1750
                                else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
176,084✔
1751
                                 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
176,084✔
1752
                                                poly_unfactorize_expression(e);
×
1753
                                if ( AT.S0->TermsLeft )   e->vflags &= ~ISZERO;
176,084✔
1754
                                else                      e->vflags |= ISZERO;
67,164✔
1755
                                if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
176,084✔
1756
                                if ( AT.S0->TermsLeft ) AR.expflags |= ISZERO;
176,084✔
1757
                                if ( AR.expchanged )    AR.expflags |= ISUNMODIFIED;
176,084✔
1758
                                AR.GetFile = 0;
176,084✔
1759
                                AT.bracketindexflag = oldbracketindexflag;
176,084✔
1760
/*
1761
                                Now copy the whole thing from fout to AR0.outfile
1762
                                Do this in one go to keep the lock occupied as short as possible
1763
*/
1764
                                SeekScratch(fout,&outposition);
176,084✔
1765
                                LOCK(AS.outputslock);
176,084✔
1766
                                oldoutfile = AB[0]->R.outfile;
176,084✔
1767
                                if ( e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
176,084✔
1768
                                        AB[0]->R.outfile = AB[0]->R.hidefile;
×
1769
                                }
1770
                                SeekScratch(AB[0]->R.outfile,&position);
176,084✔
1771
                                e->onfile = position;
176,084✔
1772
                                if ( CopyExpression(fout,AB[0]->R.outfile) < 0 ) {
176,084✔
1773
                                        AB[0]->R.outfile = oldoutfile;
×
1774
                                        UNLOCK(AS.outputslock);
×
1775
                                        MLOCK(ErrorMessageLock);
×
1776
                                        MesPrint("Error copying output of 'InParallel' expression to master. Thread: %d",identity);
×
1777
                                        MUNLOCK(ErrorMessageLock);
×
1778
                                        goto ProcErr;
×
1779
                                }
1780
                                AB[0]->R.outfile = oldoutfile;
176,084✔
1781
                                AB[0]->R.hidefile->POfull = AB[0]->R.hidefile->POfill;
176,084✔
1782
                                AB[0]->R.expflags = AR.expflags;
176,084✔
1783
                                UNLOCK(AS.outputslock);
176,084✔
1784

1785
                                if ( fout->handle >= 0 ) {        /* Now get rid of the file */
176,084✔
1786
                                        CloseFile(fout->handle);
×
1787
                                        fout->handle = -1;
×
1788
                                        remove(fout->name);
×
1789
                                        PUTZERO(fout->POposition);
×
1790
                                        PUTZERO(fout->filesize);
×
1791
                                        fout->POfill = fout->POfull = fout->PObuffer;
×
1792
                                }
1793
                                UpdateMaxSize();
176,084✔
1794

1795
                                AT.WorkPointer = oldwork;
176,084✔
1796

1797
                                } break;
176,084✔
1798
/*
1799
                        #] DOONEEXPRESSION : 
1800
                        #[ DOBRACKETS :
1801

1802
                                In case we have a bracket index we can have the worker treat
1803
                                one or more of the entries in the bracket index.
1804
                                The advantage is that identical terms will meet each other
1805
                                sooner in the sorting and hence fewer compares will be needed.
1806
                                Also this way the master doesn't need to fill the buckets.
1807
                                The main problem is the load balancing which can become very
1808
                                bad when there is a long tail without things outside the bracket.
1809
                                
1810
                                We get sent:
1811
                                1: The number of the first bracket to be done
1812
                                2: The number of the last bracket to be done
1813
*/
1814
                        case DOBRACKETS: {
124✔
1815
                                BRACKETINFO *binfo;
124✔
1816
                                BRACKETINDEX *bi;
124✔
1817
                                FILEHANDLE *fi;
124✔
1818
                                POSITION stoppos,where;
124✔
1819
                                e = Expressions + AR.CurExpr;
124✔
1820
                                binfo = e->bracketinfo;
124✔
1821
                                thr = AN.threadbuck;
124✔
1822
                                bi = &(binfo->indexbuffer[thr->firstbracket]);
124✔
1823
                                if ( AR.GetFile == 2 ) fi = AR.hidefile;
124✔
1824
                                else                   fi = AR.infile;
124✔
1825
                                where = bi->start;
124✔
1826
                                ADD2POS(where,AS.OldOnFile[AR.CurExpr]);
124✔
1827
                                SetScratch(fi,&(where));
124✔
1828
                                stoppos = binfo->indexbuffer[thr->lastbracket].next;
124✔
1829
                                ADD2POS(stoppos,AS.OldOnFile[AR.CurExpr]);
124✔
1830
                                AN.ninterms = thr->firstterm;
124✔
1831
/*
1832
                                Now we have to put the 'value' of the bracket in the
1833
                                Compress buffer.
1834
*/
1835
                                ttco = AR.CompressBuffer;
124✔
1836
                                tt = binfo->bracketbuffer + bi->bracket;
124✔
1837
                                i = *tt;
124✔
1838
                                NCOPY(ttco,tt,i)
1,590✔
1839
                                AR.CompressPointer = ttco;
124✔
1840
                                term = AT.WorkPointer;
124✔
1841
                                while ( GetTerm(BHEAD term) ) {
36,426✔
1842
                                        SeekScratch(fi,&where);
36,426✔
1843
                                        AT.WorkPointer = term + *term;
36,426✔
1844
                                        AN.IndDum = AM.IndDum;
36,426✔
1845
                                        AR.CurDum = ReNumber(BHEAD term);
36,426✔
1846
                                        if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
36,426✔
1847
                                        if ( AN.ncmod ) {
36,426✔
1848
                                                if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
×
1849
                                                else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
×
1850
                                        }
1851
                                        else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
36,426✔
1852
                                        if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
36,426✔
1853
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
×
1854
                                                PolyFunClean(BHEAD term);
×
1855
                                        }
1856
                                        if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
36,426✔
1857
                                                MLOCK(ErrorMessageLock);
×
1858
                                                MesPrint("Thread %w executing term:");
×
1859
                                                PrintTerm(term,"DoBrackets");
×
1860
                                                MUNLOCK(ErrorMessageLock);
×
1861
                                        }
1862
                                        AT.WorkPointer = term + *term;
36,426✔
1863
                                        if ( Generator(BHEAD term,0) ) {
36,426✔
1864
                                                LowerSortLevel();
×
1865
                                                MLOCK(ErrorMessageLock);
×
1866
                                                MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
×
1867
                                                MUNLOCK(ErrorMessageLock);
×
1868
                                                Terminate(-1);
×
1869
                                        }
1870
                                        AN.ninterms++;
36,426✔
1871
                                        SetScratch(fi,&(where));
36,426✔
1872
                                        if ( ISGEPOS(where,stoppos) ) break;
36,426✔
1873
                                }
1874
                                AT.WorkPointer = term;
124✔
1875
                                thr->free = BUCKETCOMINGFREE;
124✔
1876
                                break;
124✔
1877
                        }
1878
/*
1879
                        #] DOBRACKETS : 
1880
                        #[ CLEARCLOCK :
1881

1882
                        The program only comes here after a .clear
1883
*/
1884
                        case CLEARCLOCK:
×
1885
/*                                LOCK(clearclocklock); */
1886
                                sumtimerinfo[identity] += TimeCPU(1);
×
1887
                                timerinfo[identity] = TimeCPU(0);
×
1888
/*                                UNLOCK(clearclocklock); */
1889
                                break;
×
1890
/*
1891
                        #] CLEARCLOCK : 
1892
                        #[ MCTSEXPANDTREE :
1893
*/
1894
                        case MCTSEXPANDTREE:
124✔
1895
                                AT.optimtimes = AB[0]->T.optimtimes;
124✔
1896
                                find_Horner_MCTS_expand_tree();
124✔
1897
                                break;
124✔
1898
/*
1899
                        #] MCTSEXPANDTREE : 
1900
                        #[ OPTIMIZEEXPRESSION :
1901
*/
1902
                        case OPTIMIZEEXPRESSION:
60✔
1903
                                optimize_expression_given_Horner();
60✔
1904
                                break;
60✔
1905
/*
1906
                        #] OPTIMIZEEXPRESSION : 
1907
*/
1908
                        default:
×
1909
                                MLOCK(ErrorMessageLock);
×
1910
                                MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
×
1911
                                MUNLOCK(ErrorMessageLock);
×
1912
                                Terminate(-1);
×
1913
                                break;
×
1914
                }
1915
                /* we need the following update in case we are using checkpoints. then we
1916
                   need to readjust the clocks when recovering using this information */
1917
                timerinfo[identity] = TimeCPU(1);
259,706✔
1918
        }
1919
EndOfThread:;
4,056✔
1920
/*
1921
        This is the end of the thread. We cleanup and exit.
1922
        If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
1923
*/
1924
#ifdef WITHFLINT
1925
        flint_final_cleanup_thread();
2,028✔
1926
#endif
1927
        FinalizeOneThread(identity);
4,056✔
1928
        return(0);
4,056✔
1929
ProcErr:
×
1930
        Terminate(-1);
×
1931
        return(0);
×
1932
}
1933

1934
/*
1935
          #] RunThread : 
1936
          #[ RunSortBot :
1937
*/
1938
/**
1939
 *        This is the routine that represents each sortbot.
1940
 *        The model is that the sortbot waits for a 'signal'.
1941
 *        If there is a signal it wakes up, looks at what signal and then takes
1942
 *        the corresponding action. After this it goes back to sleep.
1943
 */
1944

1945
#ifdef WITHSORTBOTS
1946

1947
void *RunSortBot(void *dummy)
1,544✔
1948
{
1949
        int identity, wakeupsignal, identityretv;
1,544✔
1950
        ALLPRIVATES *B, *BB;
1,544✔
1951
        DUMMYUSE(dummy);
1,544✔
1952
        identity = SetIdentity(&identityretv);
1,544✔
1953
        threadpointers[identity] = pthread_self();
1,544✔
1954
        B = InitializeOneThread(identity);
1,544✔
1955
        while ( ( wakeupsignal = SortBotWait(identity) ) > 0 ) {
14,788✔
1956
                switch ( wakeupsignal ) {
13,248✔
1957
/*
1958
                        #[ INISORTBOT :
1959
*/
1960
                        case INISORTBOT:
6,624✔
1961
                                AR.CompressBuffer = AB[0]->R.CompressBuffer;
6,624✔
1962
                                AR.ComprTop = AB[0]->R.ComprTop;
6,624✔
1963
                                AR.CompressPointer = AB[0]->R.CompressPointer;
6,624✔
1964
                                AR.CurExpr = AB[0]->R.CurExpr;
6,624✔
1965
                                AR.PolyFun = AB[0]->R.PolyFun;
6,624✔
1966
                                AR.PolyFunInv = AB[0]->R.PolyFunInv;
6,624✔
1967
                                AR.PolyFunType = AB[0]->R.PolyFunType;
6,624✔
1968
                                AR.PolyFunExp = AB[0]->R.PolyFunExp;
6,624✔
1969
                                AR.PolyFunVar = AB[0]->R.PolyFunVar;
6,624✔
1970
                                AR.PolyFunPow = AB[0]->R.PolyFunPow;
6,624✔
1971
                                AR.SortType = AC.SortType;
6,624✔
1972
                                if ( AR.PolyFun == 0 ) { AT.SS->PolyFlag = 0; }
6,624✔
1973
                                else if ( AR.PolyFunType == 1 ) { AT.SS->PolyFlag = 1; }
344✔
1974
                                else if ( AR.PolyFunType == 2 ) {
320✔
1975
                                        if ( AR.PolyFunExp == 2
320✔
1976
                                          || AR.PolyFunExp == 3 ) AT.SS->PolyFlag = 1;
320✔
1977
                                        else                      AT.SS->PolyFlag = 2;
244✔
1978
                                }
1979
                                AT.SS->PolyWise = 0;
6,624✔
1980
                                AN.ncmod = AC.ncmod;
6,624✔
1981
                                LOCK(AT.SB.MasterBlockLock[1]);
6,624✔
1982
                                BB = AB[AT.SortBotIn1];
6,624✔
1983
                                LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
6,624✔
1984
                                BB = AB[AT.SortBotIn2];
6,624✔
1985
                                LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
6,624✔
1986
                                AT.SB.FillBlock = 1;
6,624✔
1987
                                AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
6,624✔
1988
                                SETBASEPOSITION(AN.theposition,0);
6,624✔
1989
                                break;
6,624✔
1990
/*
1991
                        #] INISORTBOT : 
1992
                        #[ RUNSORTBOT :
1993
*/
1994
                        case RUNSORTBOT:
6,624✔
1995
                                SortBotMerge(B);
6,624✔
1996
                                break;
6,624✔
1997
/*
1998
                        #] RUNSORTBOT : 
1999
                        #[ TERMINATETHREAD :
2000
*/
2001
                        case TERMINATETHREAD:
×
2002
                                goto EndOfThread;
×
2003
/*
2004
                        #] TERMINATETHREAD : 
2005
                        #[ CLEARCLOCK :
2006

2007
                        The program only comes here after a .clear
2008
*/
2009
                        case CLEARCLOCK:
×
2010
/*                                LOCK(clearclocklock); */
2011
                                sumtimerinfo[identity] += TimeCPU(1);
×
2012
                                timerinfo[identity] = TimeCPU(0);
×
2013
/*                                UNLOCK(clearclocklock); */
2014
                                break;
×
2015
/*
2016
                        #] CLEARCLOCK : 
2017
*/
2018
                        default:
×
2019
                                MLOCK(ErrorMessageLock);
×
2020
                                MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
×
2021
                                MUNLOCK(ErrorMessageLock);
×
2022
                                Terminate(-1);
×
2023
                                break;
×
2024
                }
2025
        }
2026
EndOfThread:;
1,352✔
2027
/*
2028
        This is the end of the thread. We cleanup and exit.
2029
        If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
2030
*/
2031
#ifdef WITHFLINT
2032
        flint_final_cleanup_thread();
676✔
2033
#endif
2034
        FinalizeOneThread(identity);
1,352✔
2035
        return(0);
1,352✔
2036
}
2037

2038
#endif
2039

2040
/*
2041
          #] RunSortBot : 
2042
          #[ IAmAvailable :
2043
*/
2044
/**
2045
 *        To be called by a thread when it becomes available.
2046
 *        Puts it on a stack.
2047
 *        We use a stack model. It is also possible to define a circular queue.
2048
 *        This will be tried out at a later stage.
2049
 *        One advantage of a stack could be that if we cannot feed all threads
2050
 *        more sorting is done at the threads and the master has to do less.
2051
 *
2052
 *        @param identity The identity thread that signals its availability.
2053
 */
2054

2055
void IAmAvailable(int identity)
×
2056
{
2057
        int top;
×
2058
        LOCK(availabilitylock);
×
2059
        top = topofavailables;
×
2060
        listofavailables[topofavailables++] = identity;
×
2061
        if ( top == 0 ) {
×
2062
                UNLOCK(availabilitylock);
×
2063
                LOCK(wakeupmasterlock);
×
2064
                wakeupmaster = identity;
×
2065
                pthread_cond_signal(&wakeupmasterconditions);
×
2066
                UNLOCK(wakeupmasterlock);
×
2067
        }
2068
        else {
2069
                UNLOCK(availabilitylock);
×
2070
        }
2071
}
×
2072

2073
/*
2074
          #] IAmAvailable : 
2075
          #[ GetAvailableThread :
2076
*/
2077
/**
2078
 *        Gets an available thread from the top of the stack.
2079
 *        Maybe a circular buffer model would work better. This would mean that
2080
 *        we take the lowest available worker, rather than the highest.
2081
 *        We then have to work with high water marks and low water marks.
2082
 *        (writing point and reading point). Still to be investigated.
2083
 */
2084

2085
int GetAvailableThread(void)
323,164✔
2086
{
2087
        int retval = -1;
323,164✔
2088
        LOCK(availabilitylock);
323,164✔
2089
        if ( topofavailables > 0 ) retval = listofavailables[--topofavailables];
323,164✔
2090
        UNLOCK(availabilitylock);
323,164✔
2091
        if ( retval >= 0 ) {
323,164✔
2092
/*
2093
                Make sure the thread is indeed waiting and not between
2094
                saying that it is available and starting to wait.
2095
*/
2096
                LOCK(wakeuplocks[retval]);
199,866✔
2097
                UNLOCK(wakeuplocks[retval]);
199,866✔
2098
        }
2099
        return(retval);
323,164✔
2100
}
2101

2102
/*
2103
          #] GetAvailableThread : 
2104
          #[ ConditionalGetAvailableThread :
2105
*/
2106
/**
2107
 *        Looks whether a thread is available.
2108
 *        If a thread is available it is taken from the stack of available threads.
2109
 *
2110
 *        @return the identity of an available thread or -1 if none is available.
2111
 */
2112

2113
int ConditionalGetAvailableThread(void)
×
2114
{
2115
        int retval = -1;
×
2116
        if ( topofavailables > 0 ) {
×
2117
                LOCK(availabilitylock);
×
2118
                if ( topofavailables > 0 ) {
×
2119
                        retval = listofavailables[--topofavailables];
×
2120
                }
2121
                UNLOCK(availabilitylock);
×
2122
                if ( retval >= 0 ) {
×
2123
/*
2124
                        Make sure the thread is indeed waiting and not between
2125
                        saying that it is available and starting to wait.
2126
*/
2127
                        LOCK(wakeuplocks[retval]);
×
2128
                        UNLOCK(wakeuplocks[retval]);
×
2129
                }
2130
        }
2131
        return(retval);
×
2132
}
2133

2134
/*
2135
          #] ConditionalGetAvailableThread : 
2136
          #[ GetThread :
2137
*/
2138
/**
2139
 *        Gets a given thread from the list of available threads, even if
2140
 *        it isn't on the top of the stack.
2141
 *
2142
 *        @param identity The number of the thread that we want to remove from the
2143
 *                        list of available threads.
2144
 *        @return The number of the thread if it was available. -1 otherwise.
2145
 */
2146

2147
int GetThread(int identity)
43,788✔
2148
{
2149
        int retval = -1, j;
43,788✔
2150
        LOCK(availabilitylock);
43,788✔
2151
        for ( j = 0; j < topofavailables; j++ ) {
123,212✔
2152
                if ( identity == listofavailables[j] ) break;
79,424✔
2153
        }
2154
        if ( j < topofavailables ) {
43,788✔
2155
                --topofavailables;
43,788✔
2156
                for ( ; j < topofavailables; j++ ) {
59,470✔
2157
                        listofavailables[j] = listofavailables[j+1];
15,682✔
2158
                }
2159
                retval = identity;
2160
        }
2161
        UNLOCK(availabilitylock);
43,788✔
2162
        return(retval);
43,788✔
2163
}
2164

2165
/*
2166
          #] GetThread : 
2167
          #[ ThreadWait :
2168
*/
2169
/**
2170
 *        To be called by a thread when it has nothing to do.
2171
 *        It goes to sleep and waits for a wakeup call.
2172
 *        The return value is the number of the wakeup signal.
2173
 *
2174
 *        @param identity The number of the thread.
2175
 *        @return The number of the wake-up signal.
2176
 */
2177

2178
int ThreadWait(int identity)
264,338✔
2179
{
2180
        int retval, top, j;
264,338✔
2181
        LOCK(wakeuplocks[identity]);
264,338✔
2182
        LOCK(availabilitylock);
264,338✔
2183
        top = topofavailables;
264,338✔
2184
        for ( j = topofavailables; j > 0; j-- )
444,237✔
2185
                listofavailables[j] = listofavailables[j-1];
179,899✔
2186
        listofavailables[0] = identity;
264,338✔
2187
        topofavailables++;
264,338✔
2188
        if ( top == 0 || topofavailables == numberofworkers ) {
264,338✔
2189
                UNLOCK(availabilitylock);
202,533✔
2190
                LOCK(wakeupmasterlock);
202,533✔
2191
                wakeupmaster = identity;
202,533✔
2192
                pthread_cond_signal(&wakeupmasterconditions);
202,533✔
2193
                UNLOCK(wakeupmasterlock);
202,533✔
2194
        }
2195
        else {
2196
                UNLOCK(availabilitylock);
61,805✔
2197
        }
2198
        while ( wakeup[identity] == 0 ) {
528,236✔
2199
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
264,338✔
2200
        }
2201
        retval = wakeup[identity];
263,898✔
2202
        wakeup[identity] = 0;
263,898✔
2203
        UNLOCK(wakeuplocks[identity]);
263,898✔
2204
        return(retval);
263,898✔
2205
}
2206

2207
/*
2208
          #] ThreadWait : 
2209
          #[ SortBotWait :
2210
*/
2211
 
2212
#ifdef WITHSORTBOTS
2213
/**
2214
 *        To be called by a sortbot thread when it has nothing to do.
2215
 *        It goes to sleep and waits for a wakeup call.
2216
 *        The return value is the number of the wakeup signal.
2217
 *
2218
 *        @param identity The number of the sortbot thread.
2219
 *        @return The number of the wake-up signal.
2220
 */
2221

2222
int SortBotWait(int identity)
14,788✔
2223
{
2224
        int retval;
14,788✔
2225
        LOCK(wakeuplocks[identity]);
14,788✔
2226
        LOCK(availabilitylock);
14,788✔
2227
        topsortbotavailables++;
14,788✔
2228
        if ( topsortbotavailables >= numberofsortbots ) {
14,788✔
2229
                UNLOCK(availabilitylock);
7,394✔
2230
                LOCK(wakeupsortbotlock);
7,394✔
2231
                wakeupmaster = identity;
7,394✔
2232
                pthread_cond_signal(&wakeupsortbotconditions);
7,394✔
2233
                UNLOCK(wakeupsortbotlock);
7,394✔
2234
        }
2235
        else {
2236
                UNLOCK(availabilitylock);
7,394✔
2237
        }
2238
        while ( wakeup[identity] == 0 ) {
29,388✔
2239
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
14,788✔
2240
        }
2241
        retval = wakeup[identity];
14,600✔
2242
        wakeup[identity] = 0;
14,600✔
2243
        UNLOCK(wakeuplocks[identity]);
14,600✔
2244
        return(retval);
14,600✔
2245
}
2246

2247
#endif
2248

2249
/*
2250
          #] SortBotWait : 
2251
          #[ ThreadClaimedBlock :
2252
*/
2253
/**
2254
 *        When the final sort of an expression starts the workers have to claim
2255
 *        the first block in the buffers of the master for their output.
2256
 *        The master may only continue after all workers have claimed their block
2257
 *        because otherwise it is possible that the master may claim this block for
2258
 *        reading before it has been written in.
2259
 *        Hence the master must wait till all blocks have been claimed. Then the
2260
 *        master will get signalled that it can continue.
2261
 */
2262

2263
int ThreadClaimedBlock(int identity)
19,872✔
2264
{
2265
        LOCK(availabilitylock);
19,872✔
2266
        numberclaimed++;        
19,872✔
2267
        if ( numberclaimed >= numberofworkers ) {
19,872✔
2268
                UNLOCK(availabilitylock);
6,624✔
2269
                LOCK(wakeupmasterlock);
6,624✔
2270
                wakeupmaster = identity;
6,624✔
2271
                pthread_cond_signal(&wakeupmasterconditions);
6,624✔
2272
                UNLOCK(wakeupmasterlock);
6,624✔
2273
        }
2274
        else {
2275
                UNLOCK(availabilitylock);
13,248✔
2276
        }
2277
        return(0);
19,872✔
2278
}
2279

2280
/*
2281
          #] ThreadClaimedBlock : 
2282
          #[ MasterWait :
2283
*/
2284
/**
2285
 *        To be called by the master when it has to wait for one of the
2286
 *        workers to become available.
2287
 *        It goes to sleep and waits for a wakeupmaster call.
2288
 *        The return value is the identity of the process that wakes up the master.
2289
 */
2290

2291
int MasterWait(void)
124,752✔
2292
{
2293
        int retval;
124,752✔
2294
        LOCK(wakeupmasterlock);
124,752✔
2295
        while ( wakeupmaster == 0 ) {
234,223✔
2296
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
109,471✔
2297
        }
2298
        retval = wakeupmaster;
124,752✔
2299
        wakeupmaster = 0;
124,752✔
2300
        UNLOCK(wakeupmasterlock);
124,752✔
2301
        return(retval);
124,752✔
2302
}
2303

2304
/*
2305
          #] MasterWait : 
2306
          #[ MasterWaitThread :
2307
*/
2308
/**
2309
 *        To be called by the master when it has to wait for a specific one of the
2310
 *        workers to become available.
2311
 *        The return value is the value of the signal.
2312
 */
2313

2314
int MasterWaitThread(int identity)
×
2315
{
2316
        int retval;
×
2317
        LOCK(wakeupmasterthreadlocks[identity]);
×
2318
        while ( wakeupmasterthread[identity] == 0 ) {
×
2319
                pthread_cond_wait(&(wakeupmasterthreadconditions[identity])
×
2320
                                ,&(wakeupmasterthreadlocks[identity]));
2321
        }
2322
        retval = wakeupmasterthread[identity];
×
2323
        wakeupmasterthread[identity] = 0;
×
2324
        UNLOCK(wakeupmasterthreadlocks[identity]);
×
2325
        return(retval);
×
2326
}
2327

2328
/*
2329
          #] MasterWaitThread : 
2330
          #[ MasterWaitAll :
2331
*/
2332
/**
2333
 *        To be called by the master when it has to wait for all of the
2334
 *        workers to finish a given task.
2335
 *        It goes to sleep and waits for a wakeup call in ThreadWait
2336
 */
2337

2338
void MasterWaitAll(void)
28,652✔
2339
{
2340
        LOCK(wakeupmasterlock);
28,652✔
2341
        while ( topofavailables < numberofworkers ) {
53,346✔
2342
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
24,818✔
2343
        }
2344
        UNLOCK(wakeupmasterlock);
28,528✔
2345
        return;
28,528✔
2346
}
2347

2348
/*
2349
          #] MasterWaitAll : 
2350
          #[ MasterWaitAllSortBots :
2351
*/
2352
 
2353
#ifdef WITHSORTBOTS
2354

2355
/**
2356
 *        To be called by the master when it has to wait for all of the
2357
 *        sortbots to start their task.
2358
 */
2359

2360
void MasterWaitAllSortBots(void)
8,182✔
2361
{
2362
        LOCK(wakeupsortbotlock);
8,182✔
2363
        while ( topsortbotavailables < numberofsortbots ) {
12,267✔
2364
                pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
4,085✔
2365
        }
2366
        UNLOCK(wakeupsortbotlock);
8,182✔
2367
        return;
8,182✔
2368
}
2369

2370
#endif
2371

2372
/*
2373
          #] MasterWaitAllSortBots : 
2374
          #[ MasterWaitAllBlocks :
2375
*/
2376
/**
2377
 *        To be called by the master when it has to wait for all of the
2378
 *        workers to claim their first block in the sort buffers of the master.
2379
 *        It goes to sleep and waits for a wakeup call.
2380
 */
2381

2382
void MasterWaitAllBlocks(void)
6,624✔
2383
{
2384
        LOCK(wakeupmasterlock);
6,624✔
2385
        while ( numberclaimed < numberofworkers ) {
14,265✔
2386
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
7,641✔
2387
        }
2388
        UNLOCK(wakeupmasterlock);
6,624✔
2389
        return;
6,624✔
2390
}
2391

2392
/*
2393
          #] MasterWaitAllBlocks : 
2394
          #[ WakeupThread :
2395
*/
2396
/**
2397
 *        To be called when the indicated thread needs waking up.
2398
 *        The signal number should be nonzero!
2399
 *
2400
 *        @param identity     The number of the worker to be woken up
2401
 *        @param signalnumber The signal with which it should be woken up.
2402
 */
2403

2404
void WakeupThread(int identity, int signalnumber)
278,498✔
2405
{
2406
        if ( signalnumber == 0 ) {
278,498✔
2407
                MLOCK(ErrorMessageLock);
×
2408
                MesPrint("Illegal wakeup signal for thread %d",identity);
×
2409
                MUNLOCK(ErrorMessageLock);
×
2410
                Terminate(-1);
×
2411
        }
2412
        LOCK(wakeuplocks[identity]);
278,498✔
2413
        wakeup[identity] = signalnumber;
278,498✔
2414
        pthread_cond_signal(&(wakeupconditions[identity]));
278,498✔
2415
        UNLOCK(wakeuplocks[identity]);
278,498✔
2416
}
278,498✔
2417

2418
/*
2419
          #] WakeupThread : 
2420
          #[ WakeupMasterFromThread :
2421
*/
2422
/**
2423
 *        To be called when the indicated thread needs to wake up the master.
2424
 *        The signal number should be nonzero!
2425
 *
2426
 *        @param identity     The number of the worker who wakes up the master.
2427
 *        @param signalnumber The signal with which the master should be woken up.
2428
 */
2429

2430
void WakeupMasterFromThread(int identity, int signalnumber)
×
2431
{
2432
        if ( signalnumber == 0 ) {
×
2433
                MLOCK(ErrorMessageLock);
×
2434
                MesPrint("Illegal wakeup signal for master %d",identity);
×
2435
                MUNLOCK(ErrorMessageLock);
×
2436
                Terminate(-1);
×
2437
        }
2438
        LOCK(wakeupmasterthreadlocks[identity]);
×
2439
        wakeupmasterthread[identity] = signalnumber;
×
2440
        pthread_cond_signal(&(wakeupmasterthreadconditions[identity]));
×
2441
        UNLOCK(wakeupmasterthreadlocks[identity]);
×
2442
}
×
2443

2444
/*
2445
          #] WakeupMasterFromThread : 
2446
          #[ SendOneBucket :
2447
*/
2448
/**
2449
 *        To be called when there is a full bucket and an available thread
2450
 *        It prepares the thread and then wakes it up.
2451
 */
2452

2453
int SendOneBucket(int type)
465✔
2454
{
2455
        ALLPRIVATES *B0 = AB[0];
465✔
2456
        THREADBUCKET *thr = 0;
465✔
2457
        int j, k, id;
465✔
2458
        for ( j = 0; j < numthreadbuckets; j++ ) {
850✔
2459
                if ( threadbuckets[j]->free == BUCKETFILLED ) {
850✔
2460
                        thr = threadbuckets[j];
465✔
2461
                        for ( k = j+1; k < numthreadbuckets; k++ )
2,759✔
2462
                                threadbuckets[k-1] = threadbuckets[k];
2,294✔
2463
                        threadbuckets[numthreadbuckets-1] = thr;
465✔
2464
                        break;
465✔
2465
                }
2466
        }
2467
        AN0.ninterms++;
465✔
2468
        while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
465✔
2469
/*
2470
        Prepare the thread. Give it the term and variables.
2471
*/
2472
        LoadOneThread(0,id,thr,0);
465✔
2473
        thr->busy = BUCKETASSIGNED;
465✔
2474
        thr->free = BUCKETINUSE;
465✔
2475
        numberoffullbuckets--;
465✔
2476
/*
2477
        And signal the thread to run.
2478
        Form now on we may only interfere with this bucket
2479
        1: after it has been marked BUCKETCOMINGFREE
2480
        2: when thr->busy == BUCKETDOINGTERM and then only when protected by
2481
           thr->lock. This would be for load balancing.
2482
*/
2483
        WakeupThread(id,type);
465✔
2484
/*        AN0.ninterms += thr->ddterms; */
2485
        return(0);
465✔
2486
}
2487

2488
/*
2489
          #] SendOneBucket : 
2490
          #[ InParallelProcessor :
2491
*/
2492
/**
2493
 *        We divide the expressions marked by partodo over the workers.
2494
 *        The workers are responsible for writing their results into the buffers
2495
 *        of the master (output). This is to be controlled by locks.
2496
 *        The order of the expressions may get changed this way.
2497
 *
2498
 *        The InParallel statement allows the execution of complete expressions
2499
 *        in a single worker simultaneously. This is useful for when there are
2500
 *        many short expressions. This way we don't need the bottleneck of the
2501
 *        merging by the master. The complete sort for each expression is done
2502
 *        inside its own single worker. The bottleneck here is the writing of the
2503
 *        result into the scratch system. This is now done by the workers themselves.
2504
 *        Because each expression must be contiguous, the writing should be done
2505
 *        as quickly as possible and be protected by locks.
2506
 *
2507
 *        The implementation of this statement gave a significant increase in
2508
 *        efficiency in the running of the Multiple Zeta Values program.
2509
 */
2510

2511
int InParallelProcessor(void)
3,572✔
2512
{
2513
        GETIDENTITY
3,572✔
2514
        int i, id, retval = 0, num = 0;
3,572✔
2515
        EXPRESSIONS e;
3,572✔
2516
        if ( numberofworkers >= 2 ) {
3,572✔
2517
                SetWorkerFiles();
3,572✔
2518
                for ( i = 0; i < NumExpressions; i++ ) {
540,452✔
2519
                        e = Expressions+i;
533,308✔
2520
                        if ( e->partodo <= 0 ) continue;
533,308✔
2521
                        if ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION
176,084✔
2522
                        || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION
2523
                        || e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
×
2524
                        }
2525
                        else {
2526
                                e->partodo = 0;
×
2527
                                continue;
×
2528
                        }
2529
                        if ( e->counter == 0 ) { /* Expression with zero terms */
176,084✔
2530
                                e->partodo = 0;
×
2531
                                continue;
×
2532
                        }
2533
/*
2534
                        This expression should go to an idle worker
2535
*/
2536
                        while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
289,904✔
2537
                        LoadOneThread(0,id,0,-1);
176,084✔
2538
                        AB[id]->R.exprtodo = i;
176,084✔
2539
                        WakeupThread(id,DOONEEXPRESSION);
176,084✔
2540
                        num++;
176,084✔
2541
                }
2542
/*
2543
                Now we have to wait for all workers to finish
2544
*/
2545
                if ( num > 0 ) MasterWaitAll();
3,572✔
2546

2547
                if ( AC.CollectFun ) AR.DeferFlag = 0;
3,572✔
2548
        }
2549
        else {
2550
                for ( i = 0; i < NumExpressions; i++ ) {
×
2551
                        Expressions[i].partodo = 0;
×
2552
                }
2553
        }
2554
        return(retval);
3,572✔
2555
}
2556

2557
/*
2558
          #] InParallelProcessor : 
2559
          #[ ThreadsProcessor :
2560
*/
2561
/**
2562
 *        This routine takes the role of the central part of the Processor routine
2563
 *        in the file proces.c when multiple threads are available.
2564
 *        It deals with the expressions that are not marked in the InParallel
2565
 *        statement. These are usually the large expressions. It will divide
2566
 *        the terms of these expressions over the workers, using a bucket system
2567
 *        to reduce overhead (buckets are collections of a number of terms that
2568
 *        are transferred together).
2569
 *        At the end of the expression when all terms have been assigned and 
2570
 *        workers become available again, there is a load balancing system to
2571
 *        take terms from the buckets of workers that still have to do many terms
2572
 *        and give them to idle workers. This is called first level load balancing.
2573
 *
2574
 *        A new feature is that for expressions with a bracket index the terms
2575
 *        can be distributed in collections of complete brackets (12-nov-2009).
2576
 *
2577
 *        The routine is called for each expression separately by Processor.
2578
 *
2579
 *        @param e              The expression to be executed
2580
 *        @param LastExpression Indicates whether it is the last expression in which case
2581
 *                              in the end the input scratch file can be deleted before
2582
 *                              the output is written. This saves diskspace.
2583
 */
2584

2585
int ThreadsProcessor(EXPRESSIONS e, WORD LastExpression, WORD fromspectator)
6,748✔
2586
{
2587
        ALLPRIVATES *B0 = AB[0], *B = B0;
6,748✔
2588
        int id, oldgzipCompress, endofinput = 0, j, still, k, defcount = 0, bra = 0, first = 1;
6,748✔
2589
        LONG dd = 0, ddd, thrbufsiz, thrbufsiz0, thrbufsiz2, numbucket = 0, numpasses;
6,748✔
2590
        LONG num, i;
6,748✔
2591
        WORD *oldworkpointer = AT0.WorkPointer, *tt, *ttco = 0, *t1 = 0, ter, *tstop = 0, *t2;
6,748✔
2592
        THREADBUCKET *thr = 0;
6,748✔
2593
        FILEHANDLE *oldoutfile = AR0.outfile;
6,748✔
2594
        GETTERM GetTermP = &GetTerm;
6,748✔
2595
        POSITION eonfile = AS.OldOnFile[e-Expressions];
6,748✔
2596
        numberoffullbuckets = 0;
6,748✔
2597
/*
2598
        Start up all threads. The lock needs to be around the whole loop
2599
        to keep processes from terminating quickly and putting themselves
2600
        in the list of available threads again.
2601
*/
2602
        AM.tracebackflag = 1;
6,748✔
2603

2604
        AS.sLevel = AR0.sLevel;
6,748✔
2605
        LOCK(availabilitylock);
6,748✔
2606
        topofavailables = 0;
6,748✔
2607
        for ( id = 1; id <= numberofworkers; id++ ) {
26,992✔
2608
                WakeupThread(id,STARTNEWEXPRESSION);
20,244✔
2609
        }
2610
        UNLOCK(availabilitylock);
6,748✔
2611
        NewSort(BHEAD0);
6,748✔
2612
        AN0.ninterms = 1;
6,748✔
2613
/*
2614
        Now for redefine
2615
*/
2616
        if ( AC.numpfirstnum > 0 ) {
6,748✔
2617
                for ( j = 0; j < AC.numpfirstnum; j++ ) {
1,044✔
2618
                        AC.inputnumbers[j] = -1;
572✔
2619
                }
2620
        }
2621
        MasterWaitAll();
6,748✔
2622
/*
2623
        Determine a reasonable bucketsize.
2624
        This is based on the value of AC.ThreadBucketSize and the number
2625
        of terms. We want at least 5 buckets per worker at the moment.
2626
        Some research should show whether this is reasonable.
2627

2628
        The number of terms in the expression is in e->counter
2629
*/
2630
        thrbufsiz2 = thrbufsiz = AC.ThreadBucketSize-1;
6,748✔
2631
        if ( ( e->counter / ( numberofworkers * 5 ) ) < thrbufsiz ) {
6,748✔
2632
                thrbufsiz = e->counter / ( numberofworkers * 5 ) - 1;
6,710✔
2633
                if ( thrbufsiz < 0 ) thrbufsiz = 0;
6,710✔
2634
        }
2635
        thrbufsiz0 = thrbufsiz;
6,748✔
2636
        numpasses = 5; /* this is just for trying */
6,748✔
2637
        thrbufsiz = thrbufsiz0 / (2 << numpasses);
6,748✔
2638
/*
2639
        Mark all buckets as free and take the first.
2640
*/
2641
        for ( j = 0; j < numthreadbuckets; j++ )
47,236✔
2642
                threadbuckets[j]->free = BUCKETFREE;
40,488✔
2643
        thr = threadbuckets[0];
6,748✔
2644
/*
2645
          #[ Whole brackets :
2646

2647
        First we look whether we have to work with entire brackets
2648
        This is the case when there is a non-NULL address in e->bracketinfo.
2649
        Of course we shouldn't have interference from a collect or keep statement.
2650
*/
2651
#ifdef WHOLEBRACKETS
2652
        if ( e->bracketinfo && AC.CollectFun == 0 && AR0.DeferFlag == 0 ) {
6,748✔
2653
                FILEHANDLE *curfile;
72✔
2654
                int didone = 0;
72✔
2655
                LONG num, n;
72✔
2656
                AN0.expr = e;
72✔
2657
                for ( n = 0; n < e->bracketinfo->indexfill; n++ ) {
520✔
2658
                        num = TreatIndexEntry(B0,n);
448✔
2659
                        if ( num > 0 ) {
448✔
2660
                                didone = 1;
202✔
2661
/*
2662
                                This bracket can be sent off.
2663
                                1: Look for an empty bucket
2664
*/
2665
ReTry:;
202✔
2666
                                for ( j = 0; j < numthreadbuckets; j++ ) {
1,208✔
2667
                                        switch ( threadbuckets[j]->free ) {
1,130✔
2668
                                                case BUCKETFREE:
124✔
2669
                                                        thr = threadbuckets[j];
124✔
2670
                                                        goto Found1;
124✔
2671
                                                case BUCKETCOMINGFREE:
78✔
2672
                                                        thr = threadbuckets[j];
78✔
2673
                                                        thr->free = BUCKETFREE;
78✔
2674
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
445✔
2675
                                                                threadbuckets[k-1] = threadbuckets[k];
367✔
2676
                                                        threadbuckets[numthreadbuckets-1] = thr;
78✔
2677
                                                        j--;
78✔
2678
                                                        break;
78✔
2679
                                                default:
2680
                                                        break;
2681
                                        }
2682
                                }
2683
Found1:;
78✔
2684
                                if ( j < numthreadbuckets ) {
202✔
2685
/*
2686
                                        Found an empty bucket. Fill it.
2687
*/
2688
                                        thr->firstbracket = n;
124✔
2689
                                        thr->lastbracket = n + num - 1;
124✔
2690
                                        thr->type = BUCKETDOINGBRACKET;
124✔
2691
                                        thr->free = BUCKETFILLED;
124✔
2692
                                        thr->firstterm = AN0.ninterms;
124✔
2693
                                        for ( j = n; j < n+num; j++ ) {
512✔
2694
                                                AN0.ninterms += e->bracketinfo->indexbuffer[j].termsinbracket;
388✔
2695
                                        }
2696
                                        n += num-1;
124✔
2697
                                        numberoffullbuckets++;
124✔
2698
                                        if ( topofavailables > 0 ) {
124✔
2699
                                                SendOneBucket(DOBRACKETS);
32✔
2700
                                        }
2701
                                }
2702
/*
2703
                                        All buckets are in use.
2704
                                        Look/wait for an idle worker. Give it a bucket.
2705
                                        After that, retry for a bucket
2706
*/
2707
                                else {
2708
                                        while ( topofavailables <= 0 ) {
160✔
2709
                                                MasterWait();
82✔
2710
                                        }
2711
                                        SendOneBucket(DOBRACKETS);
78✔
2712
                                        goto ReTry;
78✔
2713
                                }
2714
                        }
2715
                }
2716
                if ( didone ) {
72✔
2717
/*
2718
                        And now put the input back in the original position.
2719
*/
2720
                        switch ( e->status ) {
16✔
2721
                                case UNHIDELEXPRESSION:
×
2722
                                case UNHIDEGEXPRESSION:
2723
                                case DROPHLEXPRESSION:
2724
                                case DROPHGEXPRESSION:
2725
                                case HIDDENLEXPRESSION:
2726
                                case HIDDENGEXPRESSION:
2727
                                        curfile = AR0.hidefile;
×
2728
                                        break;
×
2729
                                default:
16✔
2730
                                        curfile = AR0.infile;
16✔
2731
                                        break;
16✔
2732
                        }
2733
                        SetScratch(curfile,&eonfile);
16✔
2734
                        GetTerm(B0,AT0.WorkPointer);
16✔
2735
/*
2736
                        Now we point the GetTerm that is used to the one that is selective
2737
*/
2738
                        GetTermP = &GetTerm2;
16✔
2739
/*
2740
                        Next wait till there is a bucket available and initialize thr to it.
2741
*/
2742
                        for(;;) {
20✔
2743
                                for ( j = 0; j < numthreadbuckets; j++ ) {
70✔
2744
                                        switch ( threadbuckets[j]->free ) {
66✔
2745
                                                case BUCKETFREE:
16✔
2746
                                                        thr = threadbuckets[j];
16✔
2747
                                                        goto Found2;
16✔
2748
                                                case BUCKETCOMINGFREE:
4✔
2749
                                                        thr = threadbuckets[j];
4✔
2750
                                                        thr->free = BUCKETFREE;
4✔
2751
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
24✔
2752
                                                                threadbuckets[k-1] = threadbuckets[k];
20✔
2753
                                                        threadbuckets[numthreadbuckets-1] = thr;
4✔
2754
                                                        j--;
4✔
2755
                                                        break;
4✔
2756
                                                default:
2757
                                                        break;
2758
                                        }
2759
                                }
2760
                                while ( topofavailables <= 0 ) {
8✔
2761
                                        MasterWait();
4✔
2762
                                }
2763
                                while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
8✔
2764
                                        SendOneBucket(DOBRACKETS);
4✔
2765
                                }
2766
                        }
2767
Found2:;
16✔
2768
                        while ( numberoffullbuckets > 0 ) {
26✔
2769
                                while ( topofavailables <= 0 ) {
22✔
2770
                                        MasterWait();
12✔
2771
                                }
2772
                                while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
20✔
2773
                                        SendOneBucket(DOBRACKETS);
10✔
2774
                                }
2775
                        }
2776
/*
2777
                        Disable the 'warming up' with smaller buckets.
2778

2779
                        numpasses = 0;
2780
                        thrbufsiz = thrbufsiz0;
2781
*/
2782
                        AN0.lastinindex = -1;
16✔
2783
                }
2784
                MasterWaitAll();
72✔
2785
        }
2786
#endif
2787
/*
2788
          #] Whole brackets : 
2789

2790
        Now the loop to start a bucket
2791
*/
2792
        for(;;) {
29,350✔
2793
                if ( fromspectator ) {
29,350✔
2794
                        ter = GetFromSpectator(thr->threadbuffer,fromspectator-1);
12✔
2795
                        if ( ter == 0 ) fromspectator = 0;
12✔
2796
                }
2797
                else {
2798
                        ter = GetTermP(B0,thr->threadbuffer);
29,338✔
2799
/*
2800
                        At this point we could check whether the input term is
2801
                        just an expression that resides in a scratch file.
2802
                        If this is the case we should store the current input info
2803
                        (file and buffer content) and redirect the input.
2804
                        At the end we can go back to where we were.
2805
                        There are two possibilities: we are in the same scratchfile
2806
                        as the main input and the other expression is still in the
2807
                        input buffer, or we have to do some reading. The reading is
2808
                        of course done in GetTerm.
2809

2810
                        How to set this up can also be studied in TestSub (in file proces.c)
2811
                        where it checks for EXPRESSION.
2812
*/
2813
                }
2814
                if ( ter < 0 ) break;
29,342✔
2815
                if ( ter == 0 ) { endofinput = 1; goto Finalize; }
29,350✔
2816
                dd = AN0.deferskipped;
22,754✔
2817
                if ( AR0.DeferFlag ) {
22,754✔
2818
                        defcount = 0;
2,448✔
2819
                        thr->deferbuffer[defcount++] = AR0.DefPosition;
2,448✔
2820
                        ttco = thr->compressbuffer; t1 = AR0.CompressBuffer; j = *t1;
2,448✔
2821
                        NCOPY(ttco,t1,j);
60,862✔
2822
                }
2823
                else if ( first && ( AC.CollectFun == 0 ) ) { /* Brackets ? */
20,306✔
2824
                        first = 0;
6,060✔
2825
                        t1 = tstop = thr->threadbuffer;
6,060✔
2826
                        tstop += *tstop; tstop -= ABS(tstop[-1]);
6,060✔
2827
                        t1++;
6,060✔
2828
                        while ( t1 < tstop ) {
14,372✔
2829
                                if ( t1[0] == HAAKJE ) { bra = 1; break; }
8,436✔
2830
                                t1 += t1[1];
8,312✔
2831
                        }
2832
                        t1 = thr->threadbuffer;
2833
                }
2834
/*
2835
                Check whether we have a collect,function going. If so execute it.
2836
*/
2837
                if ( AC.CollectFun && *(thr->threadbuffer) < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
22,754✔
2838
                        if ( ( dd = GetMoreTerms(thr->threadbuffer) ) < 0 ) {
20✔
2839
                                LowerSortLevel(); goto ProcErr;
×
2840
                        }
2841
                }
2842
/*
2843
                Check whether we have a priority task:
2844
*/
2845
                if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
22,754✔
2846
/*
2847
                Now put more terms in the bucket. Position tt after the first term
2848
*/
2849
                tt = thr->threadbuffer; tt += *tt;
22,754✔
2850
                thr->totnum = 1;
22,754✔
2851
                thr->usenum = 0;
22,754✔
2852
/*
2853
                Next we worry about the 'slow startup' in which we make the initial
2854
                buckets smaller, so that we get all threads busy as soon as possible.
2855
*/
2856
                if ( numpasses > 0 ) {
22,754✔
2857
                        numbucket++;
18,630✔
2858
                        if ( numbucket >= numberofworkers ) {
18,630✔
2859
                                numbucket = 0;
4,374✔
2860
                                numpasses--;
4,374✔
2861
                                if ( numpasses == 0 ) thrbufsiz = thrbufsiz0;
4,374✔
2862
                                else                  thrbufsiz = thrbufsiz0 / (2 << numpasses);
3,992✔
2863
                        }
2864
                        thrbufsiz2 = thrbufsiz + thrbufsiz/5; /* for completing brackets */
18,630✔
2865
                }
2866
/*
2867
                we have already 1+dd terms
2868
*/
2869
                while ( ( dd < thrbufsiz ) &&
713,736✔
2870
                        ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer/((LONG)sizeof(WORD)) - 2 ) ) {
691,134✔
2871
/*
2872
                        First check:
2873
*/
2874
                        if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
691,134✔
2875
/*
2876
                        There is room in the bucket. Fill yet another term.
2877
*/
2878
                        if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
691,134✔
2879
                        dd++;
690,982✔
2880
                        thr->totnum++;
690,982✔
2881
                        dd += AN0.deferskipped;
690,982✔
2882
                        if ( AR0.DeferFlag ) {
690,982✔
2883
                                thr->deferbuffer[defcount++] = AR0.DefPosition;
320✔
2884
                                t1 = AR0.CompressBuffer; j = *t1;
320✔
2885
                                NCOPY(ttco,t1,j);
10,522✔
2886
                        }
2887
                        if ( AC.CollectFun && *tt < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
690,982✔
2888
                                if ( ( ddd = GetMoreTerms(tt) ) < 0 ) {
×
2889
                                        LowerSortLevel(); goto ProcErr;
×
2890
                                }
2891
                                dd += ddd;
×
2892
                        }
2893
                        t1 = tt;
690,982✔
2894
                        tt += *tt;
690,982✔
2895
                }
2896
/*
2897
                Check whether there are regular brackets and if we have no DeferFlag
2898
                and no collect, we try to add more terms till we finish the current
2899
                bracket. We should however not overdo it. Let us say: up to 20%
2900
                more terms are allowed.
2901
*/
2902
                if ( bra ) {
22,754✔
2903
                        tstop = t1 + *t1; tstop -= ABS(tstop[-1]);
1,060✔
2904
                        t2 = t1+1;
1,060✔
2905
                        while ( t2 < tstop ) {
2,370✔
2906
                                if ( t2[0] == HAAKJE ) { break; }
2,370✔
2907
                                t2 += t2[1];
1,310✔
2908
                        }
2909
                        if ( t2[0] == HAAKJE ) {
1,060✔
2910
                          t2 += t2[1]; num = t2 - t1;
1,060✔
2911
                          while ( ( dd < thrbufsiz2 ) &&
1,554✔
2912
                                ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer - 2 ) ) {
504✔
2913
/*
2914
                                First check:
2915
*/
2916
                                if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
504✔
2917
/*
2918
                                There is room in the bucket. Fill yet another term.
2919
*/
2920
                                if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
504✔
2921
/*
2922
                                Same bracket?
2923
*/
2924
                                tstop = tt + *tt; tstop -= ABS(tstop[-1]);
500✔
2925
                                if ( tstop-tt < num ) { /* Different: abort */
500✔
2926
                                        AR0.KeptInHold = 1;
×
2927
                                        break;
×
2928
                                }
2929
                                for ( i = 1; i < num; i++ ) {
4,476✔
2930
                                        if ( t1[i] != tt[i] ) break;
3,982✔
2931
                                }
2932
                                if ( i < num ) { /* Different: abort */
500✔
2933
                                        AR0.KeptInHold = 1;
6✔
2934
                                        break;
6✔
2935
                                }
2936
/*
2937
                                Same bracket. We need this term.
2938
*/
2939
                                dd++;
494✔
2940
                                thr->totnum++;
494✔
2941
                                tt += *tt;
494✔
2942
                          }
2943
                        }
2944
                }
2945
                thr->ddterms = dd; /* total number of terms including keep brackets */
22,754✔
2946
                thr->firstterm = AN0.ninterms;
22,754✔
2947
                AN0.ninterms += dd;
22,754✔
2948
                *tt = 0;           /* mark end of bucket */
22,754✔
2949
                thr->free = BUCKETFILLED;
22,754✔
2950
                thr->type = BUCKETDOINGTERMS;
22,754✔
2951
                numberoffullbuckets++;
22,754✔
2952
                if ( topofavailables <= 0 && endofinput == 0 ) {
22,754✔
2953
/*
2954
                        Problem: topofavailables may already be > 0, but the
2955
                        thread has not yet gone into waiting. Can the signal get lost?
2956
                        How can we tell that a thread is waiting for a signal?
2957

2958
                        All threads are busy. Try to load up another bucket.
2959
                        In the future we could be more sophisticated.
2960
                        At the moment we load a complete bucket which could be
2961
                        1000 terms or even more.
2962
                        In principle it is better to keep a full bucket ready
2963
                        and check after each term we put in the next bucket. That
2964
                        way we don't waste time of the workers.
2965
*/
2966
                        for ( j = 0; j < numthreadbuckets; j++ ) {
60,818✔
2967
                                switch ( threadbuckets[j]->free ) {
55,633✔
2968
                                        case BUCKETFREE:
2969
                                                thr = threadbuckets[j];
6,029✔
2970
                                                if ( !endofinput ) goto NextBucket;
6,029✔
2971
/*
2972
                                                If we are at the end of the input we mark
2973
                                                the free buckets in a special way. That way
2974
                                                we don't keep running into them.
2975
*/
2976
                                                thr->free = BUCKETATEND;
2977
                                                break;
2978
                                        case BUCKETCOMINGFREE:
459✔
2979
                                                thr = threadbuckets[j];
459✔
2980
                                                thr->free = BUCKETFREE;
459✔
2981
/*
2982
                                                Bucket has just been finished.
2983
                                                Put at the end of the list. We don't want
2984
                                                an early bucket to wait to be treated last.
2985
*/
2986
                                                for ( k = j+1; k < numthreadbuckets; k++ )
2,593✔
2987
                                                        threadbuckets[k-1] = threadbuckets[k];
2,134✔
2988
                                                threadbuckets[numthreadbuckets-1] = thr;
459✔
2989
                                                j--;   /* we have to redo the same number j. */
459✔
2990
                                                break;
459✔
2991
                                        default:
2992
                                                break;
2993
                                }
2994
                        }
2995
/*
2996
                        We have no free bucket or we are at the end.
2997
                        The only thing we can do now is wait for a worker to come free,
2998
                        provided there are still buckets to send.
2999
*/
3000
                }
3001
/*
3002
                Look for the next bucket to send. There is at least one full bucket!
3003
*/
3004
                for ( j = 0; j < numthreadbuckets; j++ ) {
23,798✔
3005
                        if ( threadbuckets[j]->free == BUCKETFILLED ) {
23,798✔
3006
                                thr = threadbuckets[j];
16,725✔
3007
                                for ( k = j+1; k < numthreadbuckets; k++ )
94,851✔
3008
                                        threadbuckets[k-1] = threadbuckets[k];
78,126✔
3009
                                threadbuckets[numthreadbuckets-1] = thr;
16,725✔
3010
                                break;
16,725✔
3011
                        }
3012
                }
3013
/*
3014
                Wait for a thread to become available
3015
                The bucket we are going to use is in thr.
3016
*/
3017
DoBucket:;
18,483✔
3018
                AN0.ninterms++;
23,133✔
3019
                while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
32,547✔
3020
/*
3021
                Prepare the thread. Give it the term and variables.
3022
*/
3023
                LoadOneThread(0,id,thr,0);
23,133✔
3024
                LOCK(thr->lock);
23,133✔
3025
                thr->busy = BUCKETASSIGNED;
23,133✔
3026
                UNLOCK(thr->lock);
23,133✔
3027
                thr->free = BUCKETINUSE;
23,133✔
3028
                numberoffullbuckets--;
23,133✔
3029
/*
3030
                And signal the thread to run.
3031
                Form now on we may only interfere with this bucket
3032
                1: after it has been marked BUCKETCOMINGFREE
3033
                2: when thr->busy == BUCKETDOINGTERM and then only when protected by
3034
                   thr->lock. This would be for load balancing.
3035
*/
3036
                WakeupThread(id,LOWESTLEVELGENERATION);
23,133✔
3037
/*                AN0.ninterms += thr->ddterms; */
3038
/*
3039
                Now look whether there is another bucket filled and a worker available
3040
*/
3041
                if ( topofavailables > 0 ) {  /* there is a worker */
23,133✔
3042
                        for ( j = 0; j < numthreadbuckets; j++ ) {
90,717✔
3043
                                if ( threadbuckets[j]->free == BUCKETFILLED ) {
80,250✔
3044
                                        thr = threadbuckets[j];
4,650✔
3045
                                        for ( k = j+1; k < numthreadbuckets; k++ )
21,216✔
3046
                                                threadbuckets[k-1] = threadbuckets[k];
16,566✔
3047
                                        threadbuckets[numthreadbuckets-1] = thr;
4,650✔
3048
                                        goto DoBucket; /* and we found a bucket */
4,650✔
3049
                                }
3050
                        }
3051
/*
3052
                        no bucket is loaded but there is a thread available
3053
                        find a bucket to load. If there is none (all are USED or ATEND)
3054
                        we jump out of the loop.
3055
*/
3056
                        for ( j = 0; j < numthreadbuckets; j++ ) {
17,269✔
3057
                                switch ( threadbuckets[j]->free ) {
16,402✔
3058
                                        case BUCKETFREE:
9,635✔
3059
                                                thr = threadbuckets[j];
9,635✔
3060
                                                if ( !endofinput ) goto NextBucket;
9,635✔
3061
                                                thr->free = BUCKETATEND;
35✔
3062
                                                break;
35✔
3063
                                        case BUCKETCOMINGFREE:
3,538✔
3064
                                                thr = threadbuckets[j];
3,538✔
3065
                                                if ( endofinput ) {
3,538✔
3066
                                                        thr->free = BUCKETATEND;
2,144✔
3067
                                                }
3068
                                                else {
3069
                                                        thr->free = BUCKETFREE;
1,394✔
3070
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
8,819✔
3071
                                                                threadbuckets[k-1] = threadbuckets[k];
7,425✔
3072
                                                        threadbuckets[numthreadbuckets-1] = thr;
1,394✔
3073
                                                        j--;
1,394✔
3074
                                                }
3075
                                                break;
3076
                                        default:
3077
                                                break;
3078
                                }
3079
                        }
3080
                        if ( j >= numthreadbuckets ) break;
867✔
3081
                }
3082
                else {
3083
/*
3084
                        No worker available.
3085
                        Look for a bucket to load.
3086
                        Its number will be in "still"
3087
*/
3088
Finalize:;
8,016✔
3089
                        still = -1;
14,895✔
3090
                        for ( j = 0; j < numthreadbuckets; j++ ) {
90,768✔
3091
                                switch ( threadbuckets[j]->free ) {
82,846✔
3092
                                        case BUCKETFREE:
35,241✔
3093
                                                thr = threadbuckets[j];
35,241✔
3094
                                                if ( !endofinput ) goto NextBucket;
35,241✔
3095
                                                thr->free = BUCKETATEND;
28,268✔
3096
                                                break;
28,268✔
3097
                                        case BUCKETCOMINGFREE:
10,009✔
3098
                                                thr = threadbuckets[j];
10,009✔
3099
                                                if ( endofinput ) thr->free = BUCKETATEND;
10,009✔
3100
                                                else {
3101
                                                        thr->free = BUCKETFREE;
8,758✔
3102
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
48,930✔
3103
                                                                threadbuckets[k-1] = threadbuckets[k];
40,172✔
3104
                                                        threadbuckets[numthreadbuckets-1] = thr;
8,758✔
3105
                                                        j--;
8,758✔
3106
                                                }
3107
                                                break;
3108
                                        case BUCKETFILLED:
8,597✔
3109
                                                if ( still < 0 ) still = j;
8,597✔
3110
                                                break;
3111
                                        default:
3112
                                                break;
3113
                                }
3114
                        }
3115
                        if ( still < 0 ) {
7,922✔
3116
/*
3117
                                No buckets to be executed and no buckets FREE.
3118
                                We must be at the end. Break out of the loop.
3119
*/
3120
                                break;
3121
                        }
3122
                        thr = threadbuckets[still];
1,758✔
3123
                        for ( k = still+1; k < numthreadbuckets; k++ )
9,146✔
3124
                                threadbuckets[k-1] = threadbuckets[k];
7,388✔
3125
                        threadbuckets[numthreadbuckets-1] = thr;
1,758✔
3126
                        goto DoBucket;
1,758✔
3127
                }
3128
NextBucket:;
6,748✔
3129
        }
3130
/*
3131
        Now the stage one load balancing.
3132
        If the load has been readjusted we have again filled buckets.
3133
        In that case we jump back in the loop.
3134

3135
        Tricky point: when do the workers see the new value of AT.LoadBalancing?
3136
        It should activate the locks on thr->busy
3137
*/
3138
        if ( AC.ThreadBalancing ) {
7,031✔
3139
                for ( id = 1; id <= numberofworkers; id++ ) {
28,133✔
3140
                        AB[id]->T.LoadBalancing = 1;
21,102✔
3141
                }
3142
                if ( LoadReadjusted() ) goto Finalize;
7,031✔
3143
                for ( id = 1; id <= numberofworkers; id++ ) {
26,992✔
3144
                        AB[id]->T.LoadBalancing = 0;
20,244✔
3145
                }
3146
        }
3147
        if ( AC.ThreadBalancing ) {
6,748✔
3148
/*
3149
                The AS.Balancing flag should have Generator look for
3150
                free workers and apply the "buro" method.
3151

3152
                There is still a serious problem.
3153
                When for instance a sum_, there may be space created in a local
3154
                compiler buffer for a wildcard substitution or whatever.
3155
                Compiler buffer execution scribble space.....
3156
                This isn't copied along?
3157
                Look up ebufnum. There are 12 places with AddRHS!
3158
                Problem: one process allocates in ebuf. Then term is given to
3159
                other process. It would like to use from this ebuf, but the sender
3160
                finishes first and removes the ebuf (and/or overwrites it).
3161

3162
                Other problem: local $ variables aren't copied along.
3163
*/
3164
                AS.Balancing = 0;
6,748✔
3165
        }
3166
        MasterWaitAll();
6,748✔
3167
        AS.Balancing = 0;
6,624✔
3168
/*
3169
        When we deal with the last expression we can now remove the input
3170
        scratch file. This saves potentially much disk space (up to 1/3)
3171
*/
3172
        if ( LastExpression ) {
6,624✔
3173
                UpdateMaxSize();
2,992✔
3174
                if ( AR0.infile->handle >= 0 ) {
2,992✔
3175
                        CloseFile(AR0.infile->handle);
12✔
3176
                        AR0.infile->handle = -1;
12✔
3177
                        remove(AR0.infile->name);
12✔
3178
                        PUTZERO(AR0.infile->POposition);
12✔
3179
                        AR0.infile->POfill = AR0.infile->POfull = AR0.infile->PObuffer;
12✔
3180
                }
3181
        }
3182
/*
3183
        We order the threads to finish in the MasterMerge routine
3184
        It will start with waiting for all threads to finish.
3185
        One could make an administration in which threads that have
3186
        finished can start already with the final sort but
3187
        1: The load balancing should not make this super urgent
3188
        2: It would definitely not be very compatible with the second
3189
           stage load balancing.
3190
*/
3191
        oldgzipCompress = AR0.gzipCompress;
6,624✔
3192
        AR0.gzipCompress = 0;
6,624✔
3193
        if ( AR0.outtohide ) AR0.outfile = AR0.hidefile;
6,624✔
3194
        if ( MasterMerge() < 0 ) {
6,624✔
3195
                if ( AR0.outtohide ) AR0.outfile = oldoutfile;
×
3196
                AR0.gzipCompress = oldgzipCompress;
×
3197
                goto ProcErr;
×
3198
        }
3199
        if ( AR0.outtohide ) AR0.outfile = oldoutfile;
6,620✔
3200
        AR0.gzipCompress = oldgzipCompress;
6,620✔
3201
/*
3202
        Now wait for all threads to be ready to give them the cleaning up signal.
3203
        With the new MasterMerge routine we can do the cleanup already automatically
3204
        avoiding having to send these signals.
3205
*/
3206
        MasterWaitAll();
6,620✔
3207
        AR0.sLevel--;
6,620✔
3208
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
26,480✔
3209
                if ( GetThread(id) > 0 ) WakeupThread(id,CLEANUPEXPRESSION);
19,860✔
3210
        }
3211
        e->numdummies = 0;
6,620✔
3212
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
26,480✔
3213
                if ( AB[id]->R.MaxDum - AM.IndDum > e->numdummies )
19,860✔
3214
                        e->numdummies = AB[id]->R.MaxDum - AM.IndDum;
1,639✔
3215
                AR0.expchanged |= AB[id]->R.expchanged;
19,860✔
3216
        }
3217
/*
3218
        And wait for all to be clean.
3219
*/
3220
        MasterWaitAll();
6,620✔
3221
        AT0.WorkPointer = oldworkpointer;
6,620✔
3222
        return(0);
6,620✔
3223
ProcErr:;
3224
        return(-1);
3225
}
3226

3227
/*
3228
          #] ThreadsProcessor : 
3229
          #[ LoadReadjusted :
3230
*/
3231
/**
3232
 *        This routine does the load readjustment at the end of a module.
3233
 *        It may be that there are still some threads that have a bucket full of
3234
 *        difficult terms. In that case we steal the bucket from such a thread
3235
 *        and redistribute the terms over the available buckets to be sent to
3236
 *        the free threads. As we steal all remaining terms from the bucket
3237
 *        it can happen that eventually the same worker gets some of the terms
3238
 *        back at a later stage.
3239
 *
3240
 *        The only tricky point is the stealing process. We have to do this
3241
 *        without having to send signals or testing locks for each term processed.
3242
 *        The lock is set around thr->busy when AT.LoadBalancing == 1 but
3243
 *        when does the worker see this? (caching?)
3244
 *
3245
 *        Remark: the thr->busy == BUCKETASSIGNED flag is to prevent stealing
3246
 *        from a thread that has not done anything yet.
3247
 */
3248

3249
int LoadReadjusted(void)
7,031✔
3250
{
3251
        ALLPRIVATES *B0 = AB[0];
7,031✔
3252
        THREADBUCKET *thr = 0, *thrtogo = 0;
7,031✔
3253
        int numtogo, numfree, numbusy, n, nperbucket, extra, i, j, u, bus;
7,031✔
3254
        LONG numinput;
7,031✔
3255
        WORD *t1, *c1, *t2, *c2, *t3;
7,031✔
3256
/*
3257
        Start with waiting for at least one free processor.
3258
        We don't want the master competing for time when all are busy.
3259
*/
3260
        while ( topofavailables <= 0 ) MasterWait();
8,387✔
3261
/*
3262
        Now look for the fullest bucket and make a list of free buckets
3263
        The bad part is that most numbers can change at any moment.
3264
*/
3265
restart:;
7,052✔
3266
        numtogo = 0;
7,052✔
3267
        numfree = 0;
7,052✔
3268
        numbusy = 0;
7,052✔
3269
        for ( j = 0; j < numthreadbuckets; j++ ) {
49,364✔
3270
                thr = threadbuckets[j];
42,312✔
3271
                if ( thr->free == BUCKETFREE || thr->free == BUCKETATEND
42,312✔
3272
                || thr->free == BUCKETCOMINGFREE ) {
10,105✔
3273
                        freebuckets[numfree++] = thr;
33,940✔
3274
                }
3275
                else if ( thr->type != BUCKETDOINGTERMS ) {}
8,372✔
3276
                else if ( thr->totnum > 1 ) { /* never steal from a bucket with one term */
8,372✔
3277
                        LOCK(thr->lock);
736✔
3278
                        bus = thr->busy;
736✔
3279
                        UNLOCK(thr->lock);
736✔
3280
                        if ( thr->free == BUCKETINUSE ) {
736✔
3281
                                n = thr->totnum-thr->usenum;
531✔
3282
                                if ( bus == BUCKETASSIGNED ) numbusy++;
531✔
3283
                                else if ( ( bus != BUCKETASSIGNED )
379✔
3284
                                           && ( n > numtogo ) ) {
3285
                                        numtogo = n;
275✔
3286
                                        thrtogo = thr;
275✔
3287
                                }
3288
                        }
3289
                        else if ( bus == BUCKETTOBERELEASED
205✔
3290
                         && thr->free == BUCKETRELEASED ) {
198✔
3291
                                freebuckets[numfree++] = thr;
198✔
3292
                                thr->free = BUCKETATEND;
198✔
3293
                                LOCK(thr->lock);
198✔
3294
                                thr->busy = BUCKETPREPARINGTERM;
198✔
3295
                                UNLOCK(thr->lock);
198✔
3296
                        }
3297
                }
3298
        }
3299
        if ( numfree == 0 ) return(0); /* serious problem */
7,052✔
3300
        if ( numtogo > 0 ) {   /* provisionally there is something to be stolen */
7,052✔
3301
                thr = thrtogo;
225✔
3302
/*
3303
                If the number has changed there is good progress.
3304
                Maybe there is another thread that needs assistance.
3305
                We start all over.
3306
*/
3307
                if ( thr->totnum-thr->usenum < numtogo ) goto restart;
225✔
3308
/*
3309
                If the thread is in the term loading phase
3310
                (thr->busy == BUCKETPREPARINGTERM) we better stay away from it.
3311
                We wait now for the thread to be busy, and don't allow it
3312
                now to drop out of this state till we are done here.
3313
                This all depends on whether AT.LoadBalancing == 1 is seen by
3314
                the thread.
3315
*/
3316
                LOCK(thr->lock);
224✔
3317
                if ( thr->busy != BUCKETDOINGTERM ) {
224✔
3318
                        UNLOCK(thr->lock);
19✔
3319
                        goto restart;
19✔
3320
                }
3321
                if ( thr->totnum-thr->usenum < numtogo ) {
205✔
3322
                        UNLOCK(thr->lock);
1✔
3323
                        goto restart;
1✔
3324
                }
3325
                thr->free = BUCKETTERMINATED;
204✔
3326
/*
3327
                The above will signal the thread we want to terminate.
3328
                Next all effort goes into making sure the landing is soft.
3329
                Unfortunately we don't want to wait for a signal, because the thread
3330
                may be working for a long time on a single term.
3331
*/
3332
                if ( thr->usenum == thr->totnum ) {
204✔
3333
/*
3334
                        Terminated in the mean time or by now working on the
3335
                        last term. Try again.
3336
*/
3337
                        thr->free = BUCKETATEND;
×
3338
                        UNLOCK(thr->lock);
×
3339
                        goto restart;
×
3340
                }
3341
                goto intercepted;
204✔
3342
        }
3343
/* This has always been commented. Indeed no lock is held here. */
3344
/*        UNLOCK(thr->lock); */
3345
        if ( numbusy > 0 ) {
6,827✔
3346
                /* JD: this avoids large runtimes for tform tests under valgrind.
3347
                   What seems to happen is we return from here, goto Finalize, and
3348
                   end up in LoadReadjusted again without the threads having a
3349
                   chance to update their busy status. Then we end up here again.
3350
                   Sleep the thread for, say, 1us to allow threads to aquire the lock. */
3351
                struct timespec sleeptime;
79✔
3352
                sleeptime.tv_sec = 0;
79✔
3353
                sleeptime.tv_nsec = 1000L;
79✔
3354
                nanosleep(&sleeptime, NULL);
79✔
3355
                return(1); /* Wait a bit.... */
79✔
3356
        }
3357
        return(0);
3358
intercepted:;
204✔
3359
/*
3360
        We intercepted one successfully. Now it becomes interesting. Action:
3361
        1: determine how many terms per free bucket.
3362
        2: find the first untreated term.
3363
        3: put the terms in the free buckets.
3364

3365
        Remember: we still have the lock to avoid interference from the thread
3366
        that is being robbed. We were holding it and then jumped here with
3367
        goto intercepted.
3368
*/
3369
        numinput = thr->firstterm + thr->usenum;
204✔
3370
        nperbucket = numtogo / numfree;
204✔
3371
        extra = numtogo - nperbucket*numfree;
204✔
3372
        if ( AR0.DeferFlag ) {
204✔
3373
                t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
5✔
3374
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
15✔
3375
                t3 = t1;
5✔
3376
                if ( extra > 0 ) {
5✔
3377
                  for ( i = 0; i < extra; i++ ) {
17✔
3378
                        thrtogo = freebuckets[i];
12✔
3379
                        t2 = thrtogo->threadbuffer;
12✔
3380
                        c2 = thrtogo->compressbuffer;
12✔
3381
                        thrtogo->free = BUCKETFILLED;
12✔
3382
                        thrtogo->type = BUCKETDOINGTERMS;
12✔
3383
                        thrtogo->totnum = nperbucket+1;
12✔
3384
                        thrtogo->ddterms = 0;
12✔
3385
                        thrtogo->usenum = 0;
12✔
3386
                        thrtogo->busy = BUCKETASSIGNED;
12✔
3387
                        thrtogo->firstterm = numinput;
12✔
3388
                        numinput += nperbucket+1;
12✔
3389
                        for ( n = 0; n <= nperbucket; n++ ) {
24✔
3390
                                j = *t1; NCOPY(t2,t1,j);
300✔
3391
                                j = *c1; NCOPY(c2,c1,j);
382✔
3392
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
12✔
3393
                        }
3394
                        *t2 = *c2 = 0;
12✔
3395
                  }
3396
                }
3397
                if ( nperbucket > 0 ) {
5✔
3398
                  for ( i = extra; i < numfree; i++ ) {
×
3399
                        thrtogo = freebuckets[i];
×
3400
                        t2 = thrtogo->threadbuffer;
×
3401
                        c2 = thrtogo->compressbuffer;
×
3402
                        thrtogo->free = BUCKETFILLED;
×
3403
                        thrtogo->type = BUCKETDOINGTERMS;
×
3404
                        thrtogo->totnum = nperbucket;
×
3405
                        thrtogo->ddterms = 0;
×
3406
                        thrtogo->usenum = 0;
×
3407
                        thrtogo->busy = BUCKETASSIGNED;
×
3408
                        thrtogo->firstterm = numinput;
×
3409
                        numinput += nperbucket;
×
3410
                        for ( n = 0; n < nperbucket; n++ ) {
×
3411
                                j = *t1; NCOPY(t2,t1,j);
×
3412
                                j = *c1; NCOPY(c2,c1,j);
×
3413
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
×
3414
                        }
3415
                        *t2 = *c2 = 0;
×
3416
                  }
3417
                }
3418
        }
3419
        else {
3420
                t1 = thr->threadbuffer;
199✔
3421
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
9,595✔
3422
                t3 = t1;
199✔
3423
                if ( extra > 0 ) {
199✔
3424
                  for ( i = 0; i < extra; i++ ) {
477✔
3425
                        thrtogo = freebuckets[i];
321✔
3426
                        t2 = thrtogo->threadbuffer;
321✔
3427
                        thrtogo->free = BUCKETFILLED;
321✔
3428
                        thrtogo->type = BUCKETDOINGTERMS;
321✔
3429
                        thrtogo->totnum = nperbucket+1;
321✔
3430
                        thrtogo->ddterms = 0;
321✔
3431
                        thrtogo->usenum = 0;
321✔
3432
                        thrtogo->busy = BUCKETASSIGNED;
321✔
3433
                        thrtogo->firstterm = numinput;
321✔
3434
                        numinput += nperbucket+1;
321✔
3435
                        for ( n = 0; n <= nperbucket; n++ ) {
4,892✔
3436
                                j = *t1; NCOPY(t2,t1,j);
975,914✔
3437
                        }
3438
                        *t2 = 0;
321✔
3439
                  }
3440
                }
3441
                if ( nperbucket > 0 ) {
199✔
3442
                  for ( i = extra; i < numfree; i++ ) {
528✔
3443
                        thrtogo = freebuckets[i];
387✔
3444
                        t2 = thrtogo->threadbuffer;
387✔
3445
                        thrtogo->free = BUCKETFILLED;
387✔
3446
                        thrtogo->type = BUCKETDOINGTERMS;
387✔
3447
                        thrtogo->totnum = nperbucket;
387✔
3448
                        thrtogo->ddterms = 0;
387✔
3449
                        thrtogo->usenum = 0;
387✔
3450
                        thrtogo->busy = BUCKETASSIGNED;
387✔
3451
                        thrtogo->firstterm = numinput;
387✔
3452
                        numinput += nperbucket;
387✔
3453
                        for ( n = 0; n < nperbucket; n++ ) {
5,993✔
3454
                                j = *t1; NCOPY(t2,t1,j);
1,137,911✔
3455
                        }
3456
                        *t2 = 0;
387✔
3457
                  }
3458
                }
3459
        }
3460
        *t3 = 0;   /* This is some form of extra insurance */
204✔
3461
        if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
204✔
3462
                thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
×
3463
        }
3464
        UNLOCK(thr->lock);
204✔
3465
        return(1);
204✔
3466
}
3467

3468
/*
3469
          #] LoadReadjusted : 
3470
          #[ SortStrategy :
3471
*/
3472
/**
3473
 *        When the final sort to the scratch file should take place
3474
 *        in a thread we should redirect to a different PutOut say PutToMaster.
3475
 *        The buffer in the Master should be an integer number times the size
3476
 *        of the buffer for PutToMaster (the PObuffersize in the 'scratchfile').
3477
 *        The action should be (assume the multiple is 3):
3478
 *                Once the worker has its buffer full it fills block 1. Next 2. etc.
3479
 *                After filling block 3 the next fill will be at 1 when it is available
3480
 *                again. Becarefull to have a locked variable that indicates whether the
3481
 *                Master has started to claim all blocks 1.
3482
 *                The Master starts working once all blocks 1 are full.
3483
 *                Each Worker has an array for the blocks that tells their status. ???
3484
 *                (Maybe better the lock on the whole block).
3485
 *                There should be a lock on them. The locks will make the threads
3486
 *                wait properly. When the Master finished a block, it marks it as
3487
 *                empty. When the master reaches the end of the last block it moves
3488
 *                the remainder to the piece before block 1. Etc.
3489
 *                Once terminated the worker can do the same as currently after
3490
 *                the call to EndSort (leave control to the master).
3491
 *                The master starts after there is a signal that all blocks 1 have
3492
 *                been filled. The tricky point is this signal without having
3493
 *                threads spend time in a waiting loop.
3494
 *        Don't compress the terms. It costs more time and serves here no real
3495
 *        purpose. It only makes things slower for the master.
3496
 *
3497
 *        At the moment the scratch buffer of the workers is 1/N times the scratch
3498
 *        buffer of the master which is usually about the size of the Large buffer
3499
 *        of the master. This way we can save a factor on the scratch buffer size
3500
 *        of the workers. Alternative: let PutToMaster write directly into the
3501
 *        buffer/block of the master and leave out the scratch of the worker
3502
 *        completely.
3503
*/
3504
/*
3505
          #] SortStrategy : 
3506
          #[ PutToMaster :
3507
*/
3508
/**
3509
 *                Writes the term (uncompressed) to the masters buffers.
3510
 *                We put it inside a block. The blocks have locks. This makes
3511
 *                that we have to wait automatically when all blocks are full.
3512
 *                This routine takes the place of PutOut when making the final
3513
 *                sort in a thread.
3514
 *                It takes the place of FlushOut when the argument is NULL.
3515
 *
3516
 *                We need an initialization first in which the first MasterBlockLock
3517
 *                is set and MasterBlock is set to 1.
3518
 *                At the end we need to unlock the last block. Both actions can
3519
 *                be done in the routine that calls EndSort for the thread.
3520
 *
3521
 *                The initialization of the variables in SB is done in
3522
 *                IniSortBlocks. This is done only once but it has to wait till
3523
 *                all threads exist and the masters sort buffers have been allocated.
3524
 *
3525
 *                Note: the zero block is reserved for leftovers at the end of the
3526
 *                last block that get moved back to the front to keep the terms
3527
 *                contiguous (done in MasterMerge).
3528
 */
3529

3530
int PutToMaster(PHEAD WORD *term)
14,140,827✔
3531
{
3532
        int i,j,nexti,ret = 0;
14,140,827✔
3533
        WORD *t, *fill, *top, zero = 0;
14,140,827✔
3534
        if ( term == 0 ) { /* Mark the end of the expression */
14,140,827✔
3535
                t = &zero; j = 1;
3536
        }
3537
        else {
3538
                t = term; ret = j = *term;
14,114,347✔
3539
                if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
14,114,347✔
3540
        }
3541
        i = AT.SB.FillBlock;          /* The block we are working at */
14,140,827✔
3542
        fill = AT.SB.MasterFill[i];     /* Where we are filling */
14,140,827✔
3543
        top = AT.SB.MasterStop[i];      /* End of the block */
14,140,827✔
3544
        while ( j > 0 ) {
28,281,664✔
3545
                while ( j > 0 && fill < top ) {
376,524,046✔
3546
                        *fill++ = *t++; j--;
362,383,209✔
3547
                }
3548
                if ( j > 0 ) {
14,140,837✔
3549
/*
3550
                        We reached the end of the block.
3551
                        Get the next block and release this block.
3552
                        The order is important. This is why there should be at least
3553
                        4 blocks or deadlocks can occur.
3554
*/
3555
                        nexti = i+1;
10✔
3556
                        if ( nexti > AT.SB.MasterNumBlocks ) {
10✔
3557
                                nexti = 1;
×
3558
                        }
3559
                        LOCK(AT.SB.MasterBlockLock[nexti]);
10✔
3560
                        UNLOCK(AT.SB.MasterBlockLock[i]);
10✔
3561
                        AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
10✔
3562
                        AT.SB.FillBlock = i = nexti;
10✔
3563
                        fill = AT.SB.MasterStart[i];
10✔
3564
                        top = AT.SB.MasterStop[i];
10✔
3565
                }
3566
        }
3567
        AT.SB.MasterFill[i] = fill;
14,140,827✔
3568
        return(ret);
14,140,827✔
3569
}
3570

3571
/*
3572
          #] PutToMaster : 
3573
          #[ SortBotOut :
3574
*/
3575
 
3576
#ifdef WITHSORTBOTS
3577

3578
/**
3579
 *                This is the output routine of the SortBots.
3580
 *                It can run PutToMaster, except for the final merge.
3581
 *                In that case we need to do special things like calling PutOut.
3582
 *                Hence the first thing we have to do is to figure out where our
3583
 *                output should be going.
3584
 */
3585

3586
int
3587
SortBotOut(PHEAD WORD *term)
9,278,444✔
3588
{
3589
        WORD im;
9,278,444✔
3590

3591
        if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
9,278,444✔
3592

3593
        if ( term == 0 ) {
4,588,862✔
3594
                if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
3,310✔
3595
                ADDPOS(AT.SS->SizeInFile[0],1);
3,310✔
3596
                return(0);
3,310✔
3597
        }
3598
        else {
3599
                numberofterms++;
4,585,552✔
3600
                if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
4,585,552✔
3601
                        MLOCK(ErrorMessageLock);
×
3602
                        MesPrint("Called from MasterMerge/SortBotOut");
×
3603
                        MUNLOCK(ErrorMessageLock);
×
3604
                        return(-1);
×
3605
                }
3606
                ADDPOS(AT.SS->SizeInFile[0],im);
4,585,552✔
3607
                return(im);
4,585,552✔
3608
        }
3609
}
3610

3611
#endif
3612

3613
/*
3614
          #] SortBotOut : 
3615
          #[ MasterMerge :
3616
*/
3617
/**
3618
 *        This is the routine in which the master merges the sorted output that
3619
 *        comes from the workers. It is similar to MergePatches in sort.c from which
3620
 *        it takes much code.
3621
 *        The important concept here is that we want the master to be working as
3622
 *        little as possible because it constitutes the bottleneck.
3623
 *        The workers fill the buffers of the master. These buffers are divided
3624
 *        into parts for each worker as is done with the file patches in MergePatches
3625
 *        but now also each worker part is divided into blocks. This allows the
3626
 *        worker to fill blocks while the master is already working on blocks that
3627
 *        were filled before. The blocks are arranged in a circular fashion.
3628
 *        The whole is controlled by locks which seems faster than setting it up
3629
 *        with signals.
3630
 *
3631
 *        This routine is run by the master when we don't use the sortbots.
3632
 */
3633

3634
int MasterMerge(void)
6,624✔
3635
{
3636
        ALLPRIVATES *B0 = AB[0], *B = 0;
6,624✔
3637
        SORTING *S = AT0.SS;
6,624✔
3638
        WORD **poin, **poin2, ul, k, i, im, *m1, j;
6,624✔
3639
        WORD lpat, mpat, level, l1, l2, r1, r2, r3, c;
6,624✔
3640
        WORD *m2, *m3, r31, r33, ki, *rr;
6,624✔
3641
        UWORD *coef;
6,624✔
3642
        POSITION position;
6,624✔
3643
        FILEHANDLE *fin, *fout;
6,624✔
3644
#ifdef WITHSORTBOTS
3645
        if ( numberofworkers > 2 ) return(SortBotMasterMerge());
6,624✔
3646
#endif
3647
        fin = &S->file;
3,312✔
3648
        if ( AR0.PolyFun == 0 ) { S->PolyFlag = 0; }
3,312✔
3649
        else if ( AR0.PolyFunType == 1 ) { S->PolyFlag = 1; }
172✔
3650
        else if ( AR0.PolyFunType == 2 ) {
160✔
3651
                if ( AR0.PolyFunExp == 2
160✔
3652
                  || AR0.PolyFunExp == 3 ) S->PolyFlag = 1;
160✔
3653
                else                       S->PolyFlag = 2;
122✔
3654
        }
3655
        S->TermsLeft = 0;
3,312✔
3656
        coef = AN0.SoScratC;
3,312✔
3657
        poin = S->poina; poin2 = S->poin2a;
3,312✔
3658
        rr = AR0.CompressPointer;
3,312✔
3659
        *rr = 0;
3,312✔
3660
/*
3661
                 #[ Setup :
3662
*/
3663
        S->inNum = numberofthreads;
3,312✔
3664
        fout = AR0.outfile;
3,312✔
3665
/*
3666
        Load the patches. The threads have to finish their sort first.
3667
*/
3668
        S->lPatch = S->inNum - 1;
3,312✔
3669
/*
3670
        Claim all zero blocks. We need them anyway.
3671
        In principle the workers should never get into these.
3672
        We also claim all last blocks. This is a safety procedure that
3673
        should prevent the workers from working their way around the clock
3674
        before the master gets started again.
3675
*/
3676
        AS.MasterSort = 1;
3,312✔
3677
        numberclaimed = 0;
3,312✔
3678
        for ( i = 1; i <= S->lPatch; i++ ) {
9,936✔
3679
                B = AB[i];
6,624✔
3680
                LOCK(AT.SB.MasterBlockLock[0]);
6,624✔
3681
                LOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
6,624✔
3682
        }
3683
/*
3684
        Now wake up the threads and have them start their final sorting.
3685
        They should start with claiming their block and the master is
3686
        not allowed to continue until that has been done.
3687
        This waiting of the master will be done below in MasterWaitAllBlocks
3688
*/
3689
        for ( i = 0; i < S->lPatch; i++ ) {
9,936✔
3690
                GetThread(i+1);
6,624✔
3691
                WakeupThread(i+1,FINISHEXPRESSION);
6,624✔
3692
        }
3693
/*
3694
        Prepare the output file.
3695
*/
3696
        if ( fout->handle >= 0 ) {
3,312✔
3697
                PUTZERO(position);
×
3698
                SeekFile(fout->handle,&position,SEEK_END);
×
3699
                ADDPOS(position,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
×
3700
        }
3701
        else {
3702
                SETBASEPOSITION(position,(fout->POfill-fout->PObuffer)*sizeof(WORD));
3,312✔
3703
        }
3704
/*
3705
        Wait for all threads to finish loading their first block.
3706
*/
3707
        MasterWaitAllBlocks();
3,312✔
3708
/*
3709
        Claim all first blocks.
3710
        We don't release the last blocks.
3711
        The strategy is that we always keep the previous block.
3712
        In principle it looks like it isn't needed for the last block but
3713
        actually it is to keep the front from overrunning the tail when writing.
3714
*/
3715
        for ( i = 1; i <= S->lPatch; i++ ) {
13,244✔
3716
                B = AB[i];
6,622✔
3717
                LOCK(AT.SB.MasterBlockLock[1]);
6,622✔
3718
                AT.SB.MasterBlock = 1;
6,620✔
3719
        }
3720
/*
3721
                 #] Setup : 
3722

3723
        Now construct the tree:
3724
*/
3725
        lpat = 1;
3726
        do { lpat <<= 1; } while ( lpat < S->lPatch );
3,310✔
3727
        mpat = ( lpat >> 1 ) - 1;
3,310✔
3728
        k = lpat - S->lPatch;
3,310✔
3729
/*
3730
        k is the number of empty places in the tree. they will
3731
        be at the even positions from 2 to 2*k
3732
*/
3733
        for ( i = 1; i < lpat; i++ ) { S->tree[i] = -1; }
6,620✔
3734
        for ( i = 1; i <= k; i++ ) {
3,310✔
3735
                im = ( i * 2 ) - 1;
×
3736
                poin[im] = AB[i]->T.SB.MasterStart[AB[i]->T.SB.MasterBlock];
×
3737
                poin2[im] = poin[im] + *(poin[im]);
×
3738
                S->used[i] = im;
×
3739
                S->ktoi[im] = i-1;
×
3740
                S->tree[mpat+i] = 0;
×
3741
                poin[im-1] = poin2[im-1] = 0;
×
3742
        }
3743
        for ( i = (k*2)+1; i <= lpat; i++ ) {
9,930✔
3744
                S->used[i-k] = i;
6,620✔
3745
                S->ktoi[i] = i-k-1;
6,620✔
3746
                poin[i] = AB[i-k]->T.SB.MasterStart[AB[i-k]->T.SB.MasterBlock];
6,620✔
3747
                poin2[i] = poin[i] + *(poin[i]);
6,620✔
3748
        }
3749
/*
3750
        the array poin tells the position of the i-th element of the S->tree
3751
        'S->used' is a stack with the S->tree elements that need to be entered
3752
        into the S->tree. at the beginning this is S->lPatch. during the
3753
        sort there will be only very few elements.
3754
        poin2 is the next value of poin. it has to be determined
3755
        before the comparisons as the position or the size of the
3756
        term indicated by poin may change.
3757
        S->ktoi translates a S->tree element back to its stream number.
3758

3759
        start the sort
3760
*/
3761
        level = S->lPatch;
3,310✔
3762
/*
3763
        introduce one term
3764
*/
3765
OneTerm:
4,678,009✔
3766
        k = S->used[level];
4,681,319✔
3767
        i = k + lpat - 1;
4,681,319✔
3768
        if ( !*(poin[k]) ) {
4,681,319✔
3769
                do { if ( !( i >>= 1 ) ) goto EndOfMerge; } while ( !S->tree[i] );
9,930✔
3770
                if ( S->tree[i] == -1 ) {
3,310✔
3771
                        S->tree[i] = 0;
2,008✔
3772
                        level--;
2,008✔
3773
                        goto OneTerm;
2,008✔
3774
                }
3775
                k = S->tree[i];
1,302✔
3776
                S->used[level] = k;
1,302✔
3777
                S->tree[i] = 0;
1,302✔
3778
        }
3779
/*
3780
        move terms down the tree
3781
*/
3782
        while ( i >>= 1 ) {
9,260,251✔
3783
                if ( S->tree[i] > 0 ) {
4,674,699✔
3784
                        if ( ( c = CompareTerms(B0, poin[S->tree[i]],poin[k],(WORD)0) ) > 0 ) {
95,196✔
3785
/*
3786
                                S->tree[i] is the smaller. Exchange and go on.
3787
*/
3788
                                S->used[level] = S->tree[i];
9,554✔
3789
                                S->tree[i] = k;
9,554✔
3790
                                k = S->used[level];
9,554✔
3791
                        }
3792
                        else if ( !c ) {        /* Terms are equal */
85,642✔
3793
/*
3794
                                S->TermsLeft--;
3795
                                        Here the terms are equal and their coefficients
3796
                                        have to be added.
3797
*/
3798
                                l1 = *( m1 = poin[S->tree[i]] );
46,867✔
3799
                                l2 = *( m2 = poin[k] );
46,867✔
3800
                                if ( S->PolyWise ) {  /* Here we work with PolyFun */
46,867✔
3801
                                        WORD *tt1, *w;
1,655✔
3802
                                        tt1 = m1;
1,655✔
3803
                                        m1 += S->PolyWise;
1,655✔
3804
                                        m2 += S->PolyWise;
1,655✔
3805
                                        if ( S->PolyFlag == 2 ) {
1,655✔
3806
                                                w = poly_ratfun_add(B0,m1,m2);
1,653✔
3807
                                                if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
1,653✔
3808
                                                        MLOCK(ErrorMessageLock);
×
3809
                                                        MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
3810
                                                        MUNLOCK(ErrorMessageLock);
×
3811
                                                        Terminate(-1);
×
3812
                                                }
3813
                                                AT0.WorkPointer = w;
1,653✔
3814
                                                if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
1,653✔
3815
                                                        goto cancelled;
1,402✔
3816
                                                }
3817
                                        }
3818
                                        else {
3819
                                                w = AT0.WorkPointer;
2✔
3820
                                                if ( w + m1[1] + m2[1] > AT0.WorkTop ) {
2✔
3821
                                                        MLOCK(ErrorMessageLock);
×
3822
                                                        MesPrint("MasterMerge: A WorkSpace of %10l is too small",AM.WorkSize);
×
3823
                                                        MUNLOCK(ErrorMessageLock);
×
3824
                                                        Terminate(-1);
×
3825
                                                }
3826
                                                AddArgs(B0,m1,m2,w);
2✔
3827
                                        }
3828
                                        r1 = w[1];
253✔
3829
                                        if ( r1 <= FUNHEAD
253✔
3830
                                                || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
253✔
3831
                                                         { goto cancelled; }
×
3832
                                        if ( r1 == m1[1] ) {
253✔
3833
                                                NCOPY(m1,w,r1);
100✔
3834
                                        }
3835
                                        else if ( r1 < m1[1] ) {
249✔
3836
                                                r2 = m1[1] - r1;
20✔
3837
                                                m2 = w + r1;
20✔
3838
                                                m1 += m1[1];
20✔
3839
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
168,130✔
3840
                                                m2 = m1 - r2;
20✔
3841
                                                r1 = S->PolyWise;
20✔
3842
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
222✔
3843
                                                *m1 -= r2;
20✔
3844
                                                poin[S->tree[i]] = m1;
20✔
3845
                                        }
3846
                                        else {
3847
                                                r2 = r1 - m1[1];
229✔
3848
                                                m2 = tt1 - r2;
229✔
3849
                                                r1 = S->PolyWise;
229✔
3850
                                                m1 = tt1;
229✔
3851
                                                *m1 += r2;
229✔
3852
                                                poin[S->tree[i]] = m2;
229✔
3853
                                                NCOPY(m2,m1,r1);
1,715✔
3854
                                                r1 = w[1];
229✔
3855
                                                NCOPY(m2,w,r1);
2,642,212✔
3856
                                        }
3857
                                }
3858
#ifdef WITHFLOAT
3859
                                else if ( AT.SortFloatMode ) {
45,212✔
3860
                                        WORD *term1, *term2;
×
3861
                                        term1 = poin[S->tree[i]];
×
3862
                                        term2 = poin[k];
×
3863
                                        if ( MergeWithFloat(B0, &term1,&term2) == 0 )
×
3864
                                                goto cancelled;
×
3865
                                        poin[S->tree[i]] = term1;
×
3866
                                }
3867
#endif
3868
                                else {
3869
                                        r1 = *( m1 += l1 - 1 );
45,212✔
3870
                                        m1 -= ABS(r1) - 1;
45,212✔
3871
                                        r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
45,212✔
3872
                                        r2 = *( m2 += l2 - 1 );
45,212✔
3873
                                        m2 -= ABS(r2) - 1;
45,212✔
3874
                                        r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
45,212✔
3875

3876
                                        if ( AddRat(B0,(UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
45,212✔
3877
                                                MLOCK(ErrorMessageLock);
×
3878
                                                MesCall("MasterMerge");
×
3879
                                                MUNLOCK(ErrorMessageLock);
×
3880
                                                SETERROR(-1)
×
3881
                                        }
3882

3883
                                        if ( AN.ncmod != 0 ) {
45,212✔
3884
                                                if ( ( AC.modmode & POSNEG ) != 0 ) {
×
3885
                                                        NormalModulus(coef,&r3);
×
3886
                                                }
3887
                                                else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
×
3888
                                                        WORD ii;
×
3889
                                                        SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
×
3890
                                                        coef[r3] = 1;
×
3891
                                                        for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
×
3892
                                                }
3893
                                        }
3894
                                        r3 *= 2;
45,212✔
3895
                                        r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
45,212✔
3896
                                        if ( r3 < 0 ) r3 = -r3;
45,212✔
3897
                                        if ( r1 < 0 ) r1 = -r1;
45,212✔
3898
                                        r1 *= 2;
45,212✔
3899
                                        r31 = r3 - r1;
45,212✔
3900
                                        if ( !r3 ) {                /* Terms cancel */
45,212✔
3901
cancelled:
40,878✔
3902
                                                ul = S->used[level] = S->tree[i];
42,280✔
3903
                                                S->tree[i] = -1;
42,280✔
3904
/*
3905
                                                We skip to the next term in stream ul
3906
*/
3907
                                                im = *poin2[ul];
42,280✔
3908
                                                poin[ul] = poin2[ul];
42,280✔
3909
                                                ki = S->ktoi[ul];
42,280✔
3910
                                                if ( (poin[ul] + im + COMPINC) >=
42,280✔
3911
                                                AB[ki+1]->T.SB.MasterStop[AB[ki+1]->T.SB.MasterBlock]
42,280✔
3912
                                                && im > 0 ) {
×
3913
/*
3914
                                                        We made it to the end of the block. We have to
3915
                                                        release the previous block and claim the next.
3916
*/
3917
                                                        B = AB[ki+1];
×
3918
                                                        i = AT.SB.MasterBlock;
×
3919
                                                        if ( i == 1 ) {
×
3920
                                                                UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
×
3921
                                                        }
3922
                                                        else {
3923
                                                                UNLOCK(AT.SB.MasterBlockLock[i-1]);
×
3924
                                                        }
3925
                                                        if ( i == AT.SB.MasterNumBlocks ) {
×
3926
/*
3927
                                                                Move the remainder down into block 0
3928
*/
3929
                                                                WORD *from, *to;
×
3930
                                                                to = AT.SB.MasterStart[1];
×
3931
                                                                from = AT.SB.MasterStop[i];
×
3932
                                                                while ( from > poin[ul] ) *--to = *--from;
×
3933
                                                                poin[ul] = to;
×
3934
                                                                i = 1;
×
3935
                                                        }
3936
                                                        else { i++; }
×
3937
                                                        LOCK(AT.SB.MasterBlockLock[i]);
×
3938
                                                        AT.SB.MasterBlock = i;
×
3939
                                                        poin2[ul] = poin[ul] + im;
×
3940
                                                }
3941
                                                else {
3942
                                                        poin2[ul] += im;
42,280✔
3943
                                                }
3944
                                                S->used[++level] = k;
42,280✔
3945
                                        }
3946
                                        else if ( !r31 ) {                /* copy coef into term1 */
4,334✔
3947
                                                goto CopCof2;
4,334✔
3948
                                        }
3949
                                        else if ( r31 < 0 ) {                /* copy coef into term1
×
3950
                                                                                        and adjust the length of term1 */
3951
                                                goto CopCoef;
×
3952
                                        }
3953
                                        else {
3954
/*
3955
                                                        this is the dreaded calamity.
3956
                                                        is there enough space?
3957
*/
3958
                                                if( (poin[S->tree[i]]+l1+r31) >= poin2[S->tree[i]] ) {
×
3959
/*
3960
                                                                no space! now the special trick for which
3961
                                                                we left 2*maxlng spaces open at the beginning
3962
                                                                of each patch.
3963
*/
3964
                                                        if ( (l1 + r31)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
×
3965
                                                                MLOCK(ErrorMessageLock);
×
3966
                                                                MesPrint("MasterMerge: Coefficient overflow during sort");
×
3967
                                                                MUNLOCK(ErrorMessageLock);
×
3968
                                                                goto ReturnError;
×
3969
                                                        }
3970
                                                        m2 = poin[S->tree[i]];
×
3971
                                                        m3 = ( poin[S->tree[i]] -= r31 );
×
3972
                                                        do { *m3++ = *m2++; } while ( m2 < m1 );
×
3973
                                                        m1 = m3;
3974
                                                }
3975
CopCoef:
×
3976
                                                *(poin[S->tree[i]]) += r31;
×
3977
CopCof2:
4,334✔
3978
                                                m2 = (WORD *)coef; im = r3;
4,334✔
3979
                                                NCOPY(m1,m2,im);
13,018✔
3980
                                                *m1 = r33;
4,334✔
3981
                                        }
3982
                                }
3983
/*
3984
                                Now skip to the next term in stream k.
3985
*/
3986
NextTerm:
4,632,419✔
3987
                                im = poin2[k][0];
4,632,419✔
3988
                                poin[k] = poin2[k];
4,632,419✔
3989
                                ki = S->ktoi[k];
4,632,419✔
3990
                                if ( (poin[k] + im + COMPINC) >=
4,632,419✔
3991
                                AB[ki+1]->T.SB.MasterStop[AB[ki+1]->T.SB.MasterBlock]
4,632,419✔
3992
                                && im > 0 ) {
2✔
3993
/*
3994
                                We made it to the end of the block. We have to
3995
                                release the previous block and claim the next.
3996
*/
3997
                                        B = AB[ki+1];
2✔
3998
                                        i = AT.SB.MasterBlock;
2✔
3999
                                        if ( i == 1 ) {
2✔
4000
                                                UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
2✔
4001
                                        }
4002
                                        else {
4003
                                                UNLOCK(AT.SB.MasterBlockLock[i-1]);
×
4004
                                        }
4005
                                        if ( i == AT.SB.MasterNumBlocks ) {
2✔
4006
/*
4007
                                                Move the remainder down into block 0
4008
*/
4009
                                                WORD *from, *to;
×
4010
                                                to = AT.SB.MasterStart[1];
×
4011
                                                from = AT.SB.MasterStop[i];
×
4012
                                                while ( from > poin[k] ) *--to = *--from;
×
4013
                                                poin[k] = to;
×
4014
                                                i = 1;
×
4015
                                        }
4016
                                        else { i++; }
2✔
4017
                                        LOCK(AT.SB.MasterBlockLock[i]);
2✔
4018
                                        AT.SB.MasterBlock = i;
2✔
4019
                                        poin2[k] = poin[k] + im;
2✔
4020
                                }
4021
                                else {
4022
                                        poin2[k] += im;
4,632,417✔
4023
                                }
4024
                                goto OneTerm;
4,632,419✔
4025
                        }
4026
                }
4027
                else if ( S->tree[i] < 0 ) {
4,579,503✔
4028
                        S->tree[i] = k;
43,582✔
4029
                        level--;
43,582✔
4030
                        goto OneTerm;
43,582✔
4031
                }
4032
        }
4033
/*
4034
        found the smallest in the set. indicated by k.
4035
        write to its destination.
4036
*/
4037
        S->TermsLeft++;
4,585,552✔
4038
        if ( ( im = PutOut(B0,poin[k],&position,fout,1) ) < 0 ) {
4,585,552✔
4039
                MLOCK(ErrorMessageLock);
×
4040
                MesPrint("Called from MasterMerge with k = %d (stream %d)",k,S->ktoi[k]);
×
4041
                MUNLOCK(ErrorMessageLock);
×
4042
                goto ReturnError;
×
4043
        }
4044
        ADDPOS(S->SizeInFile[0],im);
4,585,552✔
4045
        goto NextTerm;
4,585,552✔
4046
EndOfMerge:
3,310✔
4047
        if ( FlushOut(&position,fout,1) ) goto ReturnError;
3,310✔
4048
        ADDPOS(S->SizeInFile[0],1);
3,310✔
4049
        CloseFile(fin->handle);
3,310✔
4050
        remove(fin->name);
3,310✔
4051
        fin->handle = -1;
3,310✔
4052
        position = S->SizeInFile[0];
3,310✔
4053
        MULPOS(position,sizeof(WORD));
3,310✔
4054
        S->GenTerms = 0;
3,310✔
4055
        for ( j = 1; j <= numberofworkers; j++ ) {
9,930✔
4056
                S->GenTerms += AB[j]->T.SS->GenTerms;
6,620✔
4057
        }
4058
        WriteStats(&position,STATSPOSTSORT,NOCHECKLOGTYPE);
3,310✔
4059
        Expressions[AR0.CurExpr].counter = S->TermsLeft;
3,310✔
4060
        Expressions[AR0.CurExpr].size = position;
3,310✔
4061
/*
4062
        Release all locks
4063
*/
4064
        for ( i = 1; i <= S->lPatch; i++ ) {
9,930✔
4065
                B = AB[i];
6,620✔
4066
                UNLOCK(AT.SB.MasterBlockLock[0]);
6,620✔
4067
                if ( AT.SB.MasterBlock == 1 ) {
6,620✔
4068
                        UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
6,618✔
4069
                }
4070
                else {
4071
                        UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock-1]);
2✔
4072
                }
4073
                UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock]);
6,620✔
4074
        }
4075
        AS.MasterSort = 0;
3,310✔
4076
        return(0);
3,310✔
4077
ReturnError:
4078
        for ( i = 1; i <= S->lPatch; i++ ) {
×
4079
                B = AB[i];
×
4080
                UNLOCK(AT.SB.MasterBlockLock[0]);
×
4081
                if ( AT.SB.MasterBlock == 1 ) {
×
4082
                        UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterNumBlocks]);
×
4083
                }
4084
                else {
4085
                        UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock-1]);
×
4086
                }
4087
                UNLOCK(AT.SB.MasterBlockLock[AT.SB.MasterBlock]);
×
4088
        }
4089
        AS.MasterSort = 0;
×
4090
        return(-1);
×
4091
}
4092

4093
/*
4094
          #] MasterMerge : 
4095
          #[ SortBotMasterMerge :
4096
*/
4097
 
4098
#ifdef WITHSORTBOTS
4099

4100
/**
4101
 *        This is the master routine for the final stage in a sortbot merge.
4102
 *        A sortbot merge is a merge in which the output of two workers is
4103
 *        merged into a single output which then can be given as one of two
4104
 *        streams to another sortbot. The idea is that each sortbot is responsible
4105
 *        for one one compare per term. In the end the master does the last
4106
 *        merge of only two streams and writes the result to the output.
4107
 *        There doesn't seem to be an advantage to splitting this last task.
4108
 *
4109
 *        The use of the sortbots gives a measurable improvement but it isn't
4110
 *        optimal yet.
4111
 *
4112
 *        This routine is run as master. Hence B = B0. Etc.
4113
 */
4114

4115
int SortBotMasterMerge(void)
3,312✔
4116
{
4117
        FILEHANDLE *fin, *fout;
3,312✔
4118
        ALLPRIVATES *B = AB[0], *BB;
3,312✔
4119
        POSITION position;
3,312✔
4120
        SORTING *S = AT.SS;
3,312✔
4121
        int i, j;
3,312✔
4122
/*
4123
        Get the sortbots get to claim their writing blocks.
4124
        We have to wait till all have been claimed because they also have to
4125
        claim the last writing blocks of the workers to prevent the head of
4126
        the circular buffer to overrun the tail.
4127

4128
        Before waiting we can do some needed initializations.
4129
        Also the master has to claim the last writing blocks of its input.
4130
*/
4131
        topsortbotavailables = 0;
3,312✔
4132
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
9,936✔
4133
                WakeupThread(i,INISORTBOT);
6,624✔
4134
        }
4135

4136
        AS.MasterSort = 1;
3,312✔
4137
        fout = AR.outfile;
3,312✔
4138
        numberofterms = 0;
3,312✔
4139
        AR.CompressPointer[0] = 0;
3,312✔
4140
        numberclaimed = 0;
3,312✔
4141
        BB = AB[AT.SortBotIn1];
3,312✔
4142
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
3,312✔
4143
        BB = AB[AT.SortBotIn2];
3,312✔
4144
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
3,312✔
4145

4146
        MasterWaitAllSortBots();
3,312✔
4147
/*
4148
        Now we can start up the workers. They will claim their writing blocks.
4149
        Here the master will wait till all writing blocks have been claimed.
4150
*/
4151
        for ( i = 1; i <= numberofworkers; i++ ) {
19,872✔
4152
                j = GetThread(i);
13,248✔
4153
                WakeupThread(i,FINISHEXPRESSION);
13,248✔
4154
        }
4155
/*
4156
        Prepare the output file in the mean time.
4157
*/
4158
        if ( fout->handle >= 0 ) {
3,312✔
4159
                PUTZERO(SortBotPosition);
×
4160
                SeekFile(fout->handle,&SortBotPosition,SEEK_END);
×
4161
                ADDPOS(SortBotPosition,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
×
4162
        }
4163
        else {
4164
                SETBASEPOSITION(SortBotPosition,(fout->POfill-fout->PObuffer)*sizeof(WORD));
3,312✔
4165
        }
4166
        MasterWaitAllBlocks();
3,312✔
4167
/*
4168
        Now we can start the sortbots after which the master goes in
4169
        sortbot mode to do its part of the job (the very final merge and
4170
        the writing to output file).
4171
*/
4172
        topsortbotavailables = 0;
3,312✔
4173
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
9,936✔
4174
                WakeupThread(i,RUNSORTBOT);
6,624✔
4175
        }
4176
        if ( SortBotMerge(BHEAD0) ) {
3,312✔
4177
                MLOCK(ErrorMessageLock);
×
4178
                MesPrint("Called from SortBotMasterMerge");
×
4179
                MUNLOCK(ErrorMessageLock);
×
4180
                AS.MasterSort = 0;
×
4181
                return(-1);
×
4182
        }
4183
/*
4184
        And next the cleanup
4185
*/
4186
        if ( S->file.handle >= 0 )
3,310✔
4187
        {
4188
                fin = &S->file;
×
4189
                CloseFile(fin->handle);
×
4190
                remove(fin->name);
×
4191
                fin->handle = -1;
×
4192
        }
4193
        position = S->SizeInFile[0];
3,310✔
4194
        MULPOS(position,sizeof(WORD));
3,310✔
4195
        S->GenTerms = 0;
3,310✔
4196
        for ( j = 1; j <= numberofworkers; j++ ) {
16,550✔
4197
                S->GenTerms += AB[j]->T.SS->GenTerms;
13,240✔
4198
        }
4199
        S->TermsLeft = numberofterms;
3,310✔
4200
        WriteStats(&position,STATSPOSTSORT,NOCHECKLOGTYPE);
3,310✔
4201
        Expressions[AR.CurExpr].counter = S->TermsLeft;
3,310✔
4202
        Expressions[AR.CurExpr].size = position;
3,310✔
4203
        AS.MasterSort = 0;
3,310✔
4204
/*
4205
        The next statement is to prevent one of the sortbots not having
4206
        completely cleaned up before the next module starts.
4207
        If this statement is omitted every once in a while one of the sortbots
4208
        is still running when the next expression starts and misses its
4209
        initialization. The result is usually disastrous.
4210
*/
4211
        MasterWaitAllSortBots();
3,310✔
4212

4213
        return(0);
3,310✔
4214
}
4215

4216
#endif
4217

4218
/*
4219
          #] SortBotMasterMerge : 
4220
          #[ SortBotMerge :
4221
*/
4222
 
4223
#ifdef WITHSORTBOTS
4224

4225
/**
4226
 *        This routine is run by a sortbot and merges two sorted output streams into
4227
 *        a single sorted stream.
4228
 */
4229

4230
int SortBotMerge(PHEAD0)
9,936✔
4231
{
4232
        GETBIDENTITY
4233
        ALLPRIVATES *Bin1 = AB[AT.SortBotIn1],*Bin2 = AB[AT.SortBotIn2];
9,936✔
4234
        WORD *term1, *term2, *next, *wp;
9,936✔
4235
        int blin1, blin2;        /* Current block numbers */
9,936✔
4236
        int error = 0;
9,936✔
4237
        WORD l1, l2, *m1, *m2, *w, r1, r2, r3, r33, r31, *tt1, ii;
9,936✔
4238
        WORD *to, *from, im, c;
9,936✔
4239
        UWORD *coef;
9,936✔
4240
        SORTING *S = AT.SS;
9,936✔
4241
#ifdef WITHFLOAT
4242
        WORD *fun1, *fun2, *fun3, *tstop1, *tstop2, size1, size2, size3, l3, jj, *m3;
9,936✔
4243
#endif
4244
/*
4245
        Set the pointers to the input terms and the output space
4246
*/
4247
        coef = AN.SoScratC;
9,936✔
4248
        blin1 = 1;
9,936✔
4249
        blin2 = 1;
9,936✔
4250
        if ( AT.identity == 0 ) {
9,936✔
4251
                wp = AT.WorkPointer;
3,312✔
4252
        }
4253
        else {
4254
                wp = AT.WorkPointer = AT.WorkSpace;
6,624✔
4255
        }
4256
/*
4257
        Get the locks for reading the input
4258
        This means that we can start once these locks have been cleared
4259
        which means that there will be input.
4260
*/
4261
        LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
9,936✔
4262
        LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
9,930✔
4263

4264
        term1 = Bin1->T.SB.MasterStart[blin1];
9,930✔
4265
        term2 = Bin2->T.SB.MasterStart[blin2];
9,930✔
4266
        AT.SB.FillBlock = 1;
9,930✔
4267
/*
4268
        Now the main loop. Keep going until one of the two hits the end.
4269
*/
4270
        while ( *term1 && *term2 ) {
280,279✔
4271
                if ( ( c = CompareTerms(BHEAD term1,term2,(WORD)0) ) > 0 ) {
270,349✔
4272
/*
4273
                        #[ One is smallest :
4274
*/
4275
                        if ( SortBotOut(BHEAD term1) < 0 ) {
90,185✔
4276
                                MLOCK(ErrorMessageLock);
×
4277
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4278
                                MUNLOCK(ErrorMessageLock);
×
4279
                                error = -1;
×
4280
                                goto ReturnError;
×
4281
                        }
4282
                        im = *term1;
90,185✔
4283
                        next = term1 + im;
90,185✔
4284
                        if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
90,185✔
4285
                        next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
88,676✔
4286
                                if ( blin1 == 1 ) {
×
4287
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
×
4288
                                }
4289
                                else {
4290
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
×
4291
                                }
4292
                                if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
×
4293
/*
4294
                                        Move the remainder down into block 0
4295
*/
4296
                                        to = Bin1->T.SB.MasterStart[1];
×
4297
                                        from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
×
4298
                                        while ( from > next ) *--to = *--from;
×
4299
                                        next = to;
4300
                                        blin1 = 1;
4301
                                }
4302
                                else {
4303
                                        blin1++;
×
4304
                                }
4305
                                LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
×
4306
                                Bin1->T.SB.MasterBlock = blin1;
×
4307
                        }
4308
                        term1 = next;
4309
/*
4310
                        #] One is smallest : 
4311
*/
4312
                }
4313
                else if ( c < 0 ) {
180,164✔
4314
/*
4315
                        #[ Two is smallest :
4316
*/
4317
                        if ( SortBotOut(BHEAD term2) < 0 ) {
89,187✔
4318
                                MLOCK(ErrorMessageLock);
×
4319
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4320
                                MUNLOCK(ErrorMessageLock);
×
4321
                                error = -1;
×
4322
                                goto ReturnError;
×
4323
                        }
4324
next2:                im = *term2;
89,187✔
4325
                        next = term2 + im;
180,164✔
4326
                        if ( next >= Bin2->T.SB.MasterStop[blin2] || ( *next
180,164✔
4327
                        && next+*next+COMPINC > Bin2->T.SB.MasterStop[blin2] ) ) {
178,980✔
4328
                                if ( blin2 == 1 ) {
×
4329
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
×
4330
                                }
4331
                                else {
4332
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
×
4333
                                }
4334
                                if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
×
4335
/*
4336
                                        Move the remainder down into block 0
4337
*/
4338
                                        to = Bin2->T.SB.MasterStart[1];
×
4339
                                        from = Bin2->T.SB.MasterStop[Bin2->T.SB.MasterNumBlocks];
×
4340
                                        while ( from > next ) *--to = *--from;
×
4341
                                        next = to;
4342
                                        blin2 = 1;
4343
                                }
4344
                                else {
4345
                                        blin2++;
×
4346
                                }
4347
                                LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
×
4348
                                Bin2->T.SB.MasterBlock = blin2;
×
4349
                        }
4350
                        term2 = next;
4351
/*
4352
                        #] Two is smallest : 
4353
*/
4354
                }
4355
                else {
4356
/*
4357
                        #[ Equal :
4358
*/
4359
                        l1 = *( m1 = term1 );
90,977✔
4360
                        l2 = *( m2 = term2 );
90,977✔
4361
                        if ( S->PolyWise ) {  /* Here we work with PolyFun */
90,977✔
4362
                                tt1 = m1;
2,198✔
4363
                                m1 += S->PolyWise;
2,198✔
4364
                                m2 += S->PolyWise;
2,198✔
4365
                                if ( S->PolyFlag == 2 ) {
2,198✔
4366
                                        AT.WorkPointer = wp;
2,194✔
4367
                                        w = poly_ratfun_add(BHEAD m1,m2);
2,194✔
4368
                                        if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
2,194✔
4369
                                                MLOCK(ErrorMessageLock);
×
4370
                                                MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
4371
                                                MUNLOCK(ErrorMessageLock);
×
4372
                                                Terminate(-1);
×
4373
                                        }
4374
                                        AT.WorkPointer = wp;
2,194✔
4375
                                        if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
2,194✔
4376
                                                goto cancelled;
1,882✔
4377
                                        }
4378
                                }
4379
                                else {
4380
                                        w = wp;
4✔
4381
                                        if ( w + m1[1] + m2[1] > AT.WorkTop ) {
4✔
4382
                                                MLOCK(ErrorMessageLock);
×
4383
                                                MesPrint("SortBotMerge(%d): A Maxtermsize of %10l is too small",
×
4384
                                                                AT.identity,AM.MaxTer/sizeof(WORD));
×
4385
                                                MesPrint("m1[1] = %d, m2[1] = %d, Space = %l",m1[1],m2[1],(LONG)(AT.WorkTop-wp));
×
4386
                                                PrintTerm(term1,"term1");
×
4387
                                                PrintTerm(term2,"term2");
×
4388
                                                MesPrint("PolyWise = %d",S->PolyWise);
×
4389
                                                MUNLOCK(ErrorMessageLock);
×
4390
                                                Terminate(-1);
×
4391
                                        }
4392
                                        AddArgs(BHEAD m1,m2,w);
4✔
4393
                                }
4394
                                r1 = w[1];
316✔
4395
                                if ( r1 <= FUNHEAD
316✔
4396
                                        || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
316✔
4397
                                                 { goto cancelled; }
×
4398
                                if ( r1 == m1[1] ) {
316✔
4399
                                        NCOPY(m1,w,r1);
1,116✔
4400
                                }
4401
                                else if ( r1 < m1[1] ) {
312✔
4402
                                        r2 = m1[1] - r1;
29✔
4403
                                        m2 = w + r1;
29✔
4404
                                        m1 += m1[1];
29✔
4405
                                        while ( --r1 >= 0 ) *--m1 = *--m2;
171,336✔
4406
                                        m2 = m1 - r2;
29✔
4407
                                        r1 = S->PolyWise;
29✔
4408
                                        while ( --r1 >= 0 ) *--m1 = *--m2;
328✔
4409
                                        *m1 -= r2;
29✔
4410
                                        term1 = m1;
29✔
4411
                                }
4412
                                else {
4413
                                        r2 = r1 - m1[1];
283✔
4414
                                        m2 = tt1 - r2;
283✔
4415
                                        r1 = S->PolyWise;
283✔
4416
                                        m1 = tt1;
283✔
4417
                                        *m1 += r2;
283✔
4418
                                        term1 = m2;
283✔
4419
                                        NCOPY(m2,m1,r1);
2,186✔
4420
                                        r1 = w[1];
283✔
4421
                                        NCOPY(m2,w,r1);
2,968,226✔
4422
                                }
4423
                        }
4424
#ifdef WITHFLOAT
4425
                        else if ( AT.SortFloatMode ) {
88,779✔
4426
/*
4427
                                The terms are in m1/term1 and m2/term2 and their length in l1 and l2.
4428
                                We have to locate the floats which have already been
4429
                                verified in the compare routine. Once we have the new
4430
                                term we can jump to the code that writes away the
4431
                                result after adding the rationals.
4432
*/
4433
                                tstop1 = m1+l1; size1 = tstop1[-1]; tstop1 -= ABS(size1);
×
4434
                                tstop2 = m2+l2; size2 = tstop2[-1]; tstop2 -= ABS(size2);
×
4435
                                if ( AT.SortFloatMode == 3 ) {
×
4436
                                        fun1 = m1+1;
×
4437
                                        while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
×
4438
                                                fun1 += fun1[1];
4439
                                        }
4440
                                        if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
×
4441
                                        UnpackFloat(aux1,fun1);
×
4442
                                        fun2 = m2+1;
×
4443
                                        while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
×
4444
                                                fun2 += fun2[1];
4445
                                        }
4446
                                        if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
×
4447
                                        UnpackFloat(aux2,fun2);
×
4448
                                }
4449
                                else if ( AT.SortFloatMode == 1 ) {
×
4450
                                        fun1 = m1+1;
×
4451
                                        while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
×
4452
                                                fun1 += fun1[1];
4453
                                        }
4454
                                        if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
×
4455
                                        UnpackFloat(aux1,fun1);
×
4456
                                        fun2 = tstop2;
×
4457
                                        RatToFloat(aux2,(UWORD *)fun2,size2);
×
4458
                                }
4459
                                else if ( AT.SortFloatMode == 2 ) {
×
4460
                                        fun1 = tstop1;
×
4461
                                        RatToFloat(aux1,(UWORD *)fun1,size1);
×
4462
                                        fun2 = m2+1;
×
4463
                                        while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
×
4464
                                                fun2 += fun2[1];
4465
                                        }
4466
                                        if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
×
4467
                                        UnpackFloat(aux2,fun2);
×
4468
                                }
4469
                                else {
4470
                                        MLOCK(ErrorMessageLock);
×
4471
                                        MesPrint("Illegal value %d for AT.SortFloatMode in SortBotMerge.",AT.SortFloatMode);
×
4472
                                        MUNLOCK(ErrorMessageLock);
×
4473
                                        Terminate(-1);
×
4474
                                        return(0);
×
4475
                                }
4476
                                mpf_add(aux3,aux1,aux2);
×
4477
                                size3 = mpf_sgn(aux3);
×
4478
                                if ( size3 == 0 ) { /* Cancelling! Rare! */
×
4479
                                        goto cancelled;
×
4480
                                }
4481
                                else if ( size3 < 0 ) mpf_neg(aux3,aux3);
×
4482
                                fun3 = TermMalloc("MasterMerge");
×
4483
                                PackFloat(fun3,aux3);
×
4484
                                l3 = fun3[1]+(fun1-m1)+3; /* new size */
×
4485

4486
                                if ( l3 != l1 ) {
×
4487
/*
4488
                                        Copy it all to wp
4489
*/
4490
                                        if ( (l3)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
×
4491
                                                MLOCK(ErrorMessageLock);
×
4492
                                                MesPrint("MasterMerge: Coefficient overflow during sort");
×
4493
                                                MUNLOCK(ErrorMessageLock);
×
4494
                                                goto ReturnError;
×
4495
                                        }
4496
                    m3 = wp; m2 = term1;
4497
                                        while ( m2 < fun1 ) *m3++ = *m2++;
×
4498
                                        for ( jj = 0; jj < fun3[1]; jj++ ) *m3++ = fun3[jj];
×
4499
                                        *m3++ = 1; *m3++ = 1;
×
4500
                                        *m3++ = size3 < 0 ? -3: 3;
×
4501
                                        *wp = m3-wp;
×
4502
                                        TermFree(fun3,"MasterMerge");
×
4503
                                        goto PutOutwp;
×
4504
                                }
4505
                                for ( jj = 0; jj < fun3[1]; jj++ ) fun1[jj] = fun3[jj];
×
4506
                                fun1 += fun3[1];
×
4507
                                *fun1++ = 1; *fun1++ = 1;
×
4508
                                *fun1++ = size3 < 0 ? -3: 3;
×
4509
                                *term1 = fun1-term1;
×
4510
                                TermFree(fun3,"MasterMerge");
×
4511
                        }
4512
#endif
4513
                        else {
4514
                                r1 = *( m1 += l1 - 1 );
88,779✔
4515
                                m1 -= ABS(r1) - 1;
88,779✔
4516
                                r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
88,779✔
4517
                                r2 = *( m2 += l2 - 1 );
88,779✔
4518
                                m2 -= ABS(r2) - 1;
88,779✔
4519
                                r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
88,779✔
4520

4521
                                if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
88,779✔
4522
                                        MLOCK(ErrorMessageLock);
×
4523
                                        MesCall("SortBotMerge");
×
4524
                                        MUNLOCK(ErrorMessageLock);
×
4525
                                        SETERROR(-1)
×
4526
                                }
4527

4528
                                if ( AN.ncmod != 0 ) {
88,779✔
4529
                                        if ( ( AC.modmode & POSNEG ) != 0 ) {
×
4530
                                                NormalModulus(coef,&r3);
×
4531
                                        }
4532
                                        else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
×
4533
                                                SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
×
4534
                                                coef[r3] = 1;
×
4535
                                                for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
×
4536
                                        }
4537
                                }
4538
                                if ( !r3 ) { goto cancelled; }
88,779✔
4539
                                r3 *= 2;
10,504✔
4540
                                r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
10,504✔
4541
                                if ( r3 < 0 ) r3 = -r3;
10,504✔
4542
                                if ( r1 < 0 ) r1 = -r1;
10,504✔
4543
                                r1 *= 2;
10,504✔
4544
                                r31 = r3 - r1;
10,504✔
4545
                                if ( !r31 ) {                /* copy coef into term1 */
10,504✔
4546
                                        m2 = (WORD *)coef; im = r3;
4547
                                        NCOPY(m1,m2,im);
31,577✔
4548
                                        *m1 = r33;
10,503✔
4549
                                }
4550
                                else {
4551
                                        to = wp; from = term1;
4552
                                        while ( from < m1 ) *to++ = *from++;
2✔
4553
                                        from = (WORD *)coef; im = r3;
1✔
4554
                                        NCOPY(to,from,im);
7✔
4555
                                        *to++ = r33;
1✔
4556
                                        wp[0] = to - wp;
1✔
4557
PutOutwp:
1✔
4558
                                        if ( SortBotOut(BHEAD wp) < 0 ) {
1✔
4559
                                                MLOCK(ErrorMessageLock);
×
4560
                                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4561
                                                MUNLOCK(ErrorMessageLock);
×
4562
                                                error = -1;
×
4563
                                                goto ReturnError;
×
4564
                                        }
4565
                                        goto cancelled;
1✔
4566
                                }
4567
                        }
4568
                        if ( SortBotOut(BHEAD term1) < 0 ) {
10,819✔
4569
                                MLOCK(ErrorMessageLock);
×
4570
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4571
                                MUNLOCK(ErrorMessageLock);
×
4572
                                error = -1;
×
4573
                                goto ReturnError;
×
4574
                        }
4575
cancelled:;                /* Now we need two new terms */
10,819✔
4576
                        im = *term1;
90,977✔
4577
                        next = term1 + im;
90,977✔
4578
                        if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
90,977✔
4579
                        next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
90,811✔
4580
                                if ( blin1 == 1 ) {
×
4581
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
×
4582
                                }
4583
                                else {
4584
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
×
4585
                                }
4586
                                if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
×
4587
/*
4588
                                        Move the remainder down into block 0
4589
*/
4590
                                        to = Bin1->T.SB.MasterStart[1];
×
4591
                                        from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
×
4592
                                        while ( from > next ) *--to = *--from;
×
4593
                                        next = to;
4594
                                        blin1 = 1;
4595
                                }
4596
                                else {
4597
                                        blin1++;
×
4598
                                }
4599
                                LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
×
4600
                                Bin1->T.SB.MasterBlock = blin1;
×
4601
                        }
4602
                        term1 = next;
90,977✔
4603
                        goto next2;
90,977✔
4604
/*
4605
                        #] Equal : 
4606
*/
4607
                }
4608
        }
4609
/*
4610
        Copy the tail
4611
*/
4612
        if ( *term1 ) {
9,930✔
4613
/*
4614
                        #[ Tail in one :
4615
*/
4616
                while ( *term1 ) {
4,896,284✔
4617
                        if ( SortBotOut(BHEAD term1) < 0 ) {
4,891,643✔
4618
                                MLOCK(ErrorMessageLock);
×
4619
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4620
                                MUNLOCK(ErrorMessageLock);
×
4621
                                error = -1;
×
4622
                                goto ReturnError;
×
4623
                        }
4624
                        im = *term1;
4,891,643✔
4625
                        next = term1 + im;
4,891,643✔
4626
                        if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
4,891,643✔
4627
                        next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
4,887,002✔
4628
                                if ( blin1 == 1 ) {
4✔
4629
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
2✔
4630
                                }
4631
                                else {
4632
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
2✔
4633
                                }
4634
                                if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4✔
4635
/*
4636
                                        Move the remainder down into block 0
4637
*/
4638
                                        to = Bin1->T.SB.MasterStart[1];
×
4639
                                        from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
×
4640
                                        while ( from > next ) *--to = *--from;
×
4641
                                        next = to;
4642
                                        blin1 = 1;
4643
                                }
4644
                                else {
4645
                                        blin1++;
4✔
4646
                                }
4647
                                LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4✔
4648
                                Bin1->T.SB.MasterBlock = blin1;
4✔
4649
                        }
4650
                        term1 = next;
4651
                }
4652
/*
4653
                        #] Tail in one : 
4654
*/
4655
        }
4656
        else if ( *term2 ) {
5,289✔
4657
/*
4658
                        #[ Tail in two :
4659
*/
4660
                while ( *term2 ) {
4,189,181✔
4661
                        if ( SortBotOut(BHEAD term2) < 0 ) {
4,186,679✔
4662
                                MLOCK(ErrorMessageLock);
×
4663
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4664
                                MUNLOCK(ErrorMessageLock);
×
4665
                                error = -1;
×
4666
                                goto ReturnError;
×
4667
                        }
4668
                        im = *term2;
4,186,679✔
4669
                        next = term2 + im;
4,186,679✔
4670
                        if ( next >= Bin2->T.SB.MasterStop[blin2] || ( *next
4,186,679✔
4671
                        && next+*next+COMPINC > Bin2->T.SB.MasterStop[blin2] ) ) {
4,184,177✔
4672
                                if ( blin2 == 1 ) {
4✔
4673
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
2✔
4674
                                }
4675
                                else {
4676
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
2✔
4677
                                }
4678
                                if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4✔
4679
/*
4680
                                        Move the remainder down into block 0
4681
*/
4682
                                        to = Bin2->T.SB.MasterStart[1];
×
4683
                                        from = Bin2->T.SB.MasterStop[Bin2->T.SB.MasterNumBlocks];
×
4684
                                        while ( from > next ) *--to = *--from;
×
4685
                                        next = to;
4686
                                        blin2 = 1;
4687
                                }
4688
                                else {
4689
                                        blin2++;
4✔
4690
                                }
4691
                                LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4✔
4692
                                Bin2->T.SB.MasterBlock = blin2;
4✔
4693
                        }
4694
                        term2 = next;
4695
                }
4696
/*
4697
                        #] Tail in two : 
4698
*/
4699
        }
4700
        SortBotOut(BHEAD 0);
9,930✔
4701
ReturnError:;
9,930✔
4702
/*
4703
        Release all locks
4704
*/
4705
        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1]);
9,930✔
4706
        if ( blin1 > 1 ) {
9,930✔
4707
                UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
2✔
4708
        }
4709
        else {
4710
                UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
9,928✔
4711
        }
4712
        UNLOCK(Bin2->T.SB.MasterBlockLock[blin2]);
9,930✔
4713
        if ( blin2 > 1 ) {
9,930✔
4714
                UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
2✔
4715
        }
4716
        else {
4717
                UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
9,928✔
4718
        }
4719
        if ( AT.identity > 0 ) {
9,930✔
4720
                UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
6,620✔
4721
        }
4722
/*
4723
        And that was all folks
4724
*/
4725
        return(error);
4726
}
4727

4728
#endif
4729

4730
/*
4731
          #] SortBotMerge : 
4732
          #[ IniSortBlocks :
4733
*/
4734
 
4735
static int SortBlocksInitialized = 0;
4736

4737
/**
4738
 *        Initializes the blocks in the sort buffers of the master.
4739
 *        These blocks are needed to keep both the workers and the master working
4740
 *        simultaneously. See also the commentary at the routine MasterMerge.
4741
 */
4742

4743
int IniSortBlocks(int numworkers)
1,560✔
4744
{
4745
        ALLPRIVATES *B;
1,560✔
4746
        SORTING *S;
1,560✔
4747
        LONG totalsize, workersize, blocksize, numberofterms;
1,560✔
4748
        int maxter, id, j;
1,560✔
4749
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
1,560✔
4750
        WORD *w;
1,560✔
4751

4752
        if ( SortBlocksInitialized ) return(0);
1,560✔
4753
        SortBlocksInitialized = 1;
1,560✔
4754
        if ( numworkers == 0 ) return(0);
1,560✔
4755

4756
#ifdef WITHSORTBOTS
4757
        if ( numworkers > 2 ) {
1,544✔
4758
                numparts = 2*numworkers - 2;
772✔
4759
                numberofblocks = numberofblocks/2;
772✔
4760
        }
4761
        else {
4762
                numparts = numworkers;
4763
        }
4764
#else
4765
        numparts = numworkers;
4766
#endif
4767
        S = AM.S0;
1,544✔
4768
        totalsize = S->LargeSize + S->SmallEsize;
1,544✔
4769
        workersize = totalsize / numparts;
1,544✔
4770
        maxter = AM.MaxTer/sizeof(WORD);
1,544✔
4771
        blocksize = ( workersize - maxter )/numberofblocks;
1,544✔
4772
        numberofterms = blocksize / maxter;
1,544✔
4773
        if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
1,544✔
4774
/*
4775
                This should have been taken care of in RecalcSetups.
4776
*/
4777
                MesPrint("We have a problem with the size of the blocks in IniSortBlocks");
×
4778
                Terminate(-1);
×
4779
        }
4780
/*
4781
        Layout:  For each worker
4782
                                block 0: size is maxter WORDS
4783
                                numberofblocks blocks of size blocksize WORDS
4784
*/
4785
        w = S->lBuffer;
1,544✔
4786
        if ( w == 0 ) w = S->sBuffer;
1,544✔
4787
        for ( id = 1; id <= numparts; id++ ) {
7,720✔
4788
                B = AB[id];
6,176✔
4789
                AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
12,352✔
4790
                        sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
6,176✔
4791
                AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
6,176✔
4792
                AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
6,176✔
4793
                AT.SB.MasterStop = AT.SB.MasterFill  + (numberofblocks+1);
6,176✔
4794
                AT.SB.MasterNumBlocks = numberofblocks;
6,176✔
4795
                AT.SB.MasterBlock = 0;
6,176✔
4796
                AT.SB.FillBlock = 0;
6,176✔
4797
                AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
6,176✔
4798
                w += maxter;
6,176✔
4799
                AT.SB.MasterStop[0] = w;
6,176✔
4800
                AT.SB.MasterBlockLock[0] = dummylock;
6,176✔
4801
                for ( j = 1; j <= numberofblocks; j++ ) {
44,776✔
4802
                        AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
38,600✔
4803
                        w += blocksize;
38,600✔
4804
                        AT.SB.MasterStop[j] = w;
38,600✔
4805
                        AT.SB.MasterBlockLock[j] = dummylock;
38,600✔
4806
                }
4807
        }
4808
        if ( w > S->sTop2 ) {
1,544✔
4809
                MesPrint("Counting problem in IniSortBlocks");
×
4810
                Terminate(-1);
×
4811
        }
4812
        return(0);
4813
}
4814

4815
/*
4816
          #] IniSortBlocks : 
4817
          #[ UpdateSortBlocks :
4818
*/
4819
 
4820
/**
4821
 *        A version of IniSortBlocks which only updates the pointers in the master's
4822
 *        buffer, to be used after reallocation of that buffer.
4823
 */
4824
int UpdateSortBlocks(int numworkers)
16✔
4825
{
4826
        ALLPRIVATES *B;
16✔
4827
        SORTING *S;
16✔
4828
        LONG totalsize, workersize, blocksize, numberofterms;
16✔
4829
        int maxter, id, j;
16✔
4830
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
16✔
4831
        WORD *w;
16✔
4832

4833
        if ( numworkers == 0 ) return(0);
16✔
4834

4835
#ifdef WITHSORTBOTS
4836
        if ( numworkers > 2 ) {
16✔
4837
                numparts = 2*numworkers - 2;
8✔
4838
                numberofblocks = numberofblocks/2;
8✔
4839
        }
4840
        else {
4841
                numparts = numworkers;
4842
        }
4843
#else
4844
        numparts = numworkers;
4845
#endif
4846
        S = AM.S0;
16✔
4847
        totalsize = S->LargeSize + S->SmallEsize;
16✔
4848
        workersize = totalsize / numparts;
16✔
4849
        maxter = AM.MaxTer/sizeof(WORD);
16✔
4850
        blocksize = ( workersize - maxter )/numberofblocks;
16✔
4851
        numberofterms = blocksize / maxter;
16✔
4852
        if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
16✔
4853
/*
4854
                This should have been taken care of in RecalcSetups.
4855
*/
4856
                MesPrint("We have a problem with the size of the blocks in UpdateSortBlocks");
×
4857
                Terminate(-1);
×
4858
        }
4859
/*
4860
        Layout:  For each worker
4861
                                block 0: size is maxter WORDS
4862
                                numberofblocks blocks of size blocksize WORDS
4863
*/
4864
        w = S->lBuffer;
16✔
4865
        if ( w == 0 ) w = S->sBuffer;
16✔
4866
        for ( id = 1; id <= numparts; id++ ) {
80✔
4867
                B = AB[id];
64✔
4868
                AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
64✔
4869
                w += maxter;
64✔
4870
                AT.SB.MasterStop[0] = w;
64✔
4871
                for ( j = 1; j <= numberofblocks; j++ ) {
464✔
4872
                        AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
400✔
4873
                        w += blocksize;
400✔
4874
                        AT.SB.MasterStop[j] = w;
400✔
4875
                }
4876
        }
4877
        if ( w > S->sTop2 ) {
16✔
4878
                MesPrint("Counting problem in UpdateSortBlocks");
×
4879
                Terminate(-1);
×
4880
        }
4881
        return(0);
4882
}
4883

4884
/*
4885
          #] UpdateSortBlocks : 
4886
          #[ DefineSortBotTree :
4887
*/
4888
 
4889
#ifdef WITHSORTBOTS
4890

4891
/**
4892
 *        To be used in a sortbot merge. It initializes the whole sortbot
4893
 *        system by telling the sortbot which threads provide their input.
4894
 */
4895

4896
void DefineSortBotTree(void)
1,560✔
4897
{
4898
        ALLPRIVATES *B;
1,560✔
4899
        int n, i, from;
1,560✔
4900
        if ( numberofworkers <= 2 ) return;
1,560✔
4901
        n = numberofworkers*2-2;
772✔
4902
        for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
2,316✔
4903
                B = AB[i];
1,544✔
4904
                AT.SortBotIn1 = from++;
1,544✔
4905
                AT.SortBotIn2 = from++;
1,544✔
4906
        }
4907
        B = AB[0];
772✔
4908
        AT.SortBotIn1 = from++;
772✔
4909
        AT.SortBotIn2 = from++;
772✔
4910
}
4911

4912
#endif
4913

4914
/*
4915
          #] DefineSortBotTree : 
4916
          #[ GetTerm2 :
4917

4918
        Routine does a GetTerm but only when a bracket index is involved and
4919
        only from brackets that have been judged not suitable for treatment
4920
        as complete brackets by a single worker. Whether or not a bracket should
4921
        be treated by a single worker is decided by TreatIndexEntry
4922
*/
4923

4924
WORD GetTerm2(PHEAD WORD *term)
3,818✔
4925
{
4926
        WORD *ttco, *tt, retval;
3,818✔
4927
        LONG n,i;
3,818✔
4928
        FILEHANDLE *fi;
3,818✔
4929
        EXPRESSIONS e = AN.expr;
3,818✔
4930
        BRACKETINFO *b  = e->bracketinfo;
3,818✔
4931
        BRACKETINDEX *bi = b->indexbuffer;
3,818✔
4932
        POSITION where, eonfile = AS.OldOnFile[e-Expressions], bstart, bnext;
3,818✔
4933
/*
4934
        1: Get the current position.
4935
*/
4936
        switch ( e->status ) {
3,818✔
4937
                case UNHIDELEXPRESSION:
×
4938
                case UNHIDEGEXPRESSION:
4939
                case DROPHLEXPRESSION:
4940
                case DROPHGEXPRESSION:
4941
                case HIDDENLEXPRESSION:
4942
                case HIDDENGEXPRESSION:
4943
                        fi = AR.hidefile;
×
4944
                        break;
×
4945
                default:
3,818✔
4946
                        fi = AR.infile;
3,818✔
4947
                        break;
3,818✔
4948
        }
4949
        if ( AR.KeptInHold ) {
3,818✔
4950
                retval = GetTerm(BHEAD term);
6✔
4951
                return(retval);
6✔
4952
        }
4953
        SeekScratch(fi,&where);
3,812✔
4954
        if ( AN.lastinindex < 0 ) {
3,812✔
4955
/*
4956
                We have to test whether we have to do the first bracket
4957
*/
4958
                if ( ( n = TreatIndexEntry(BHEAD 0) ) <= 0 ) {
16✔
4959
                        AN.lastinindex = n;
×
4960
                        where = bi[n].start;
×
4961
                        ADD2POS(where,eonfile);
×
4962
                        SetScratch(fi,&where);
×
4963
/*
4964
                        Put the bracket in the Compress buffer.
4965
*/
4966
                        ttco = AR.CompressBuffer;
×
4967
                        tt = b->bracketbuffer + bi[0].bracket;
×
4968
                        i = *tt;
×
4969
                        NCOPY(ttco,tt,i)
×
4970
                        AR.CompressPointer = ttco;
×
4971
                        retval = GetTerm(BHEAD term);
×
4972
                        return(retval);
×
4973
                }
4974
                else AN.lastinindex = n-1;
16✔
4975
        }
4976
/*
4977
        2: Find the corresponding index number
4978
           a: test whether it is in the current bracket
4979
*/
4980
        n = AN.lastinindex;
3,812✔
4981
        bstart = bi[n].start;
3,812✔
4982
        ADD2POS(bstart,eonfile);
3,812✔
4983
        bnext = bi[n].next;
3,812✔
4984
        ADD2POS(bnext,eonfile);
3,812✔
4985
        if ( ISLESSPOS(bstart,where) && ISLESSPOS(where,bnext) ) {
3,812✔
4986
                retval = GetTerm(BHEAD term);
3,700✔
4987
                return(retval);
3,700✔
4988
        }
4989
        for ( n++ ; n < b->indexfill; n++ ) {
220✔
4990
                i = TreatIndexEntry(BHEAD n);
200✔
4991
                if ( i <= 0 ) {
200✔
4992
/*
4993
                        Put the bracket in the Compress buffer.
4994
*/
4995
                        ttco = AR.CompressBuffer;
92✔
4996
                        tt = b->bracketbuffer + bi[n].bracket;
92✔
4997
                        i = *tt;
92✔
4998
                        NCOPY(ttco,tt,i)
1,100✔
4999
                        AR.CompressPointer = ttco;
92✔
5000
                        AN.lastinindex = n;
92✔
5001
                        where = bi[n].start;
92✔
5002
                        ADD2POS(where,eonfile);
92✔
5003
                        SetScratch(fi,&(where));
92✔
5004
                        retval = GetTerm(BHEAD term);
92✔
5005
                        return(retval);
92✔
5006
                }
5007
                else n += i - 1;
108✔
5008
        }
5009
        return(0);
5010
}
5011

5012
/*
5013
          #] GetTerm2 : 
5014
          #[ TreatIndexEntry :
5015
*/
5016
/**
5017
 *        Routine has to decide whether a bracket has to be sent as a complete
5018
 *        bracket to a worker or whether it has to be treated by the bucket system.
5019
 *        Return value is positive when we should send it as a complete bracket and
5020
 *        0 when it should be done via the buckets.
5021
 *        The positive return value indicates how many brackets should be treated.
5022
 */
5023
 
5024
int TreatIndexEntry(PHEAD LONG n)
664✔
5025
{
5026
        BRACKETINFO *b  = AN.expr->bracketinfo;
664✔
5027
        LONG numbra = b->indexfill - 1, i;
664✔
5028
        LONG totterms;
664✔
5029
        BRACKETINDEX *bi;
664✔
5030
        POSITION pos1, average;
664✔
5031
/*
5032
        1: number of the bracket should be such that there is one bucket
5033
           for each worker remaining.
5034
*/
5035
        if ( ( numbra - n ) <= numberofworkers ) return(0);
664✔
5036
/*
5037
        2: size of the bracket contents should be less than what remains in
5038
           the expression divided by the number of workers.
5039
*/
5040
        bi = b->indexbuffer;
376✔
5041
        DIFPOS(pos1,bi[numbra].next,bi[n].next);  /* Size of what remains */
376✔
5042
        BASEPOSITION(average) = DIVPOS(pos1,(3*numberofworkers));
376✔
5043
        DIFPOS(pos1,bi[n].next,bi[n].start);      /* Size of the current bracket */
376✔
5044
        if ( ISLESSPOS(average,pos1) ) return(0);
376✔
5045
/*
5046
        It passes.
5047
        Now check whether we can do more brackets
5048
*/
5049
        totterms = bi->termsinbracket;
248✔
5050
        if ( totterms > 2*AC.ThreadBucketSize ) return(1);
248✔
5051
        for ( i = 1; i < numbra-n; i++ ) {
760✔
5052
                DIFPOS(pos1,bi[n+i].next,bi[n].start); /* Size of the combined brackets */
760✔
5053
                if ( ISLESSPOS(average,pos1) ) return(i);
760✔
5054
                totterms += bi->termsinbracket;
528✔
5055
                if ( totterms > 2*AC.ThreadBucketSize ) return(i+1);
528✔
5056
        }
5057
/*
5058
        We have a problem at the end of the system. Just do one.
5059
*/
5060
        return(1);
5061
}
5062

5063
/*
5064
          #] TreatIndexEntry : 
5065
          #[ SetHideFiles :
5066
*/
5067

5068
void SetHideFiles(void) {
114,124✔
5069
        int i;
114,124✔
5070
        ALLPRIVATES *B, *B0 = AB[0];
114,124✔
5071
        for ( i = 1; i <= numberofworkers; i++ ) {
456,496✔
5072
                B = AB[i];
342,372✔
5073
                AR.hidefile->handle = AR0.hidefile->handle;
342,372✔
5074
                if ( AR.hidefile->handle < 0 ) {
342,372✔
5075
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
342,372✔
5076
                        AR.hidefile->POstop = AR0.hidefile->POstop;
342,372✔
5077
                        AR.hidefile->POfill = AR0.hidefile->POfill;
342,372✔
5078
                        AR.hidefile->POfull = AR0.hidefile->POfull;
342,372✔
5079
                        AR.hidefile->POsize = AR0.hidefile->POsize;
342,372✔
5080
                        AR.hidefile->POposition = AR0.hidefile->POposition;
342,372✔
5081
                        AR.hidefile->filesize = AR0.hidefile->filesize;
342,372✔
5082
                }
5083
                else {
5084
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
5085
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
5086
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
5087
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
5088
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
5089
                        PUTZERO(AR.hidefile->POposition);
×
5090
                }
5091
        }
5092
}
114,124✔
5093

5094
/*
5095
          #] SetHideFiles : 
5096
          #[ IniFbufs :
5097
*/
5098

5099
void IniFbufs(void)
1,560✔
5100
{
5101
        int i;
1,560✔
5102
        for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
7,752✔
5103
                IniFbuffer(AB[i]->T.fbufnum);
6,192✔
5104
        }
5105
}
1,560✔
5106

5107
/*
5108
          #] IniFbufs : 
5109
          #[ SetMods :
5110
*/
5111

5112
void SetMods(void)
4✔
5113
{
5114
        ALLPRIVATES *B;
4✔
5115
        int i, n, j;
4✔
5116
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
20✔
5117
                B = AB[j];
16✔
5118
                AN.ncmod = AC.ncmod;
16✔
5119
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
16✔
5120
                n = ABS(AN.ncmod);
16✔
5121
                AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
16✔
5122
                for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
32✔
5123
        }
5124
}
4✔
5125

5126
/*
5127
          #] SetMods : 
5128
          #[ UnSetMods :
5129
*/
5130

5131
void UnSetMods(void)
4✔
5132
{
5133
        ALLPRIVATES *B;
4✔
5134
        int j;
4✔
5135
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
20✔
5136
                B = AB[j];
16✔
5137
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
16✔
5138
                AN.cmod = 0;
16✔
5139
        }
5140
}
4✔
5141

5142
/*
5143
          #] UnSetMods : 
5144
          #[ find_Horner_MCTS_expand_tree_threaded :
5145
*/
5146
 
5147
void find_Horner_MCTS_expand_tree_threaded(void) {
124✔
5148
        int id;
124✔
5149
        while (( id = GetAvailableThread() ) < 0)
188✔
5150
                MasterWait();        
64✔
5151
        WakeupThread(id,MCTSEXPANDTREE);
124✔
5152
}
124✔
5153

5154
/*
5155
          #] find_Horner_MCTS_expand_tree_threaded : 
5156
          #[ optimize_expression_given_Horner_threaded :
5157
*/
5158
 
5159
extern void optimize_expression_given_Horner_threaded(void) {
60✔
5160
        int id;
60✔
5161
        while (( id = GetAvailableThread() ) < 0)
60✔
5162
                MasterWait();        
×
5163
        WakeupThread(id,OPTIMIZEEXPRESSION);
60✔
5164
}
60✔
5165

5166
/*
5167
          #] optimize_expression_given_Horner_threaded : 
5168
*/
5169

5170
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc