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

form-dev / form / 15701338753

17 Jun 2025 07:49AM UTC coverage: 50.382% (-0.004%) from 50.386%
15701338753

Pull #662

github

web-flow
Merge f1f68c050 into 207386593
Pull Request #662: Cleanup: change VOID into void

178 of 245 new or added lines in 34 files covered. (72.65%)

2 existing lines in 1 file now uncovered.

41784 of 82935 relevant lines covered (50.38%)

2640008.85 hits per line

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

77.56
/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
#ifdef WITHFLOAT
66
#include <gmp.h>
67

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

98
static THREADBUCKET **threadbuckets, **freebuckets;
99
static int numthreadbuckets;
100
static int numberoffullbuckets;
101

102
/* static int numberbusy = 0; */
103

104
INILOCK(dummylock)
105
INIRWLOCK(dummyrwlock)
106
static pthread_cond_t dummywakeupcondition = PTHREAD_COND_INITIALIZER;
107

108
#ifdef WITHSORTBOTS
109
static POSITION SortBotPosition;
110
static int numberofsortbots;
111
static INILOCK(wakeupsortbotlock)
112
static pthread_cond_t wakeupsortbotconditions = PTHREAD_COND_INITIALIZER;
113
static int topsortbotavailables = 0;
114
static LONG numberofterms;
115
#endif
116

117
/*
118
          #] Variables : 
119
          #[ Identity :
120
                 #[ StartIdentity :
121
*/
122
/**
123
 *        To be called once when we start up the threads.
124
 *        Starts our identity administration.
125
 */
126

127
void StartIdentity(void)
1,300✔
128
{
129
        pthread_key_create(&identitykey,FinishIdentity);
1,300✔
130
}
1,300✔
131

132
/*
133
                 #] StartIdentity : 
134
                 #[ FinishIdentity :
135
*/
136
/**
137
 *        The library needs a finishing routine
138
 */
139

140
void FinishIdentity(void *keyp)
4,592✔
141
{
142
        DUMMYUSE(keyp);
4,592✔
143
/*        free(keyp); */
144
}
4,592✔
145

146
/*
147
                 #] FinishIdentity : 
148
                 #[ SetIdentity :
149
*/
150
/**
151
 *        Assigns an integer value to a thread, starting at zero.
152
 */
153

154
int SetIdentity(int *identityretval)
6,420✔
155
{
156
/*
157
#ifdef _MSC_VER
158
        printf("addr %d\n",&numberofthreadslock);
159
        printf("size %d\n",sizeof(numberofthreadslock));
160
#endif
161
*/
162
        LOCK(numberofthreadslock);
6,420✔
163
        *identityretval = identityofthreads++;
6,420✔
164
        UNLOCK(numberofthreadslock);
6,420✔
165
        pthread_setspecific(identitykey,(void *)identityretval);
6,420✔
166
        return(*identityretval);
6,420✔
167
}
168

169
/*
170
                 #] SetIdentity : 
171
                 #[ WhoAmI :
172
*/
173

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

184
int WhoAmI(void)
70,157,036✔
185
{
186
        int *identity;
70,157,036✔
187
/*
188
        First a fast exit for when there is at most one thread
189
*/
190
        if ( identityofthreads <= 1 ) return(0);
70,157,036✔
191
/*
192
        Now the reading of the key.
193
        According to the book the statement should read:
194

195
        pthread_getspecific(identitykey,(void **)(&identity));
196

197
        but according to the information in pthread.h it is:
198
*/
199
        identity = (int *)pthread_getspecific(identitykey);
70,153,972✔
200
        return(*identity);
70,153,972✔
201
}
202

203
/*
204
                 #] WhoAmI : 
205
                 #[ BeginIdentities :
206
*/
207
/**
208
 *        Starts up the identity registration. This is the routine to be called
209
 *        at the startup of TFORM.
210
 */
211

212
void BeginIdentities(void)
1,300✔
213
{
214
        StartIdentity();
1,300✔
215
        SetIdentity(&identityretval);
1,300✔
216
}
1,300✔
217

218
/*
219
                 #] BeginIdentities : 
220
          #] Identity : 
221
          #[ StartHandleLock :
222
*/
223
/**
224
 *        Routine to be called at the startup of TFORM.
225
 *        We have this routine because we would like to keep all access to TFORM
226
 *        specific data in this file.
227
 */
228

229
void StartHandleLock(void)
1,300✔
230
{
231
        AM.handlelock = dummyrwlock;
1,300✔
232
}
1,300✔
233

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

255
int StartAllThreads(int number)
1,296✔
256
{
257
        int identity, j, dummy, mul;
1,296✔
258
        ALLPRIVATES *B;
1,296✔
259
        pthread_t thethread;
1,296✔
260
        identity = WhoAmI();
1,296✔
261

262
#ifdef WITHSORTBOTS
263
        timerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"timerinfo");
1,296✔
264
        sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"sumtimerinfo");
1,296✔
265
        for ( j = 0; j < number*2; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
11,568✔
266
        mul = 2;
1,296✔
267
#else
268
        timerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"timerinfo");
269
        sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number,"sumtimerinfo");
270
        for ( j = 0; j < number; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
271
        mul = 1;
272
#endif
273
 
274
        listofavailables = (int *)Malloc1(sizeof(int)*(number+1),"listofavailables");
1,296✔
275
        threadpointers = (pthread_t *)Malloc1(sizeof(pthread_t)*number*mul,"threadpointers");
1,296✔
276
        AB = (ALLPRIVATES **)Malloc1(sizeof(ALLPRIVATES *)*number*mul,"Private structs");
1,296✔
277

278
        wakeup = (int *)Malloc1(sizeof(int)*number*mul,"wakeup");
1,296✔
279
        wakeuplocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeuplocks");
1,296✔
280
        wakeupconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupconditions");
1,296✔
281
        wakeupconditionattributes = (pthread_condattr_t *)
2,592✔
282
                        Malloc1(sizeof(pthread_condattr_t)*number*mul,"wakeupconditionattributes");
1,296✔
283

284
        wakeupmasterthread = (int *)Malloc1(sizeof(int)*number*mul,"wakeupmasterthread");
1,296✔
285
        wakeupmasterthreadlocks = (pthread_mutex_t *)Malloc1(sizeof(pthread_mutex_t)*number*mul,"wakeupmasterthreadlocks");
1,296✔
286
        wakeupmasterthreadconditions = (pthread_cond_t *)Malloc1(sizeof(pthread_cond_t)*number*mul,"wakeupmasterthread");
1,296✔
287

288
        numberofthreads = number;
1,296✔
289
        numberofworkers = number - 1;
1,296✔
290
        threadpointers[identity] = pthread_self();
1,296✔
291
        topofavailables = 0;
1,296✔
292
        for ( j = 1; j < number; j++ ) {
5,136✔
293
                if ( pthread_create(&thethread,NULL,RunThread,(void *)(&dummy)) )
3,840✔
294
                        goto failure;
×
295
        }
296
/*
297
        Now we initialize the master at the same time that the workers are doing so.
298
*/
299
        B = InitializeOneThread(identity);
1,296✔
300
        AR.infile = &(AR.Fscr[0]);
1,296✔
301
        AR.outfile = &(AR.Fscr[1]);
1,296✔
302
        AR.hidefile = &(AR.Fscr[2]);
1,296✔
303
        AM.sbuflock = dummylock;
1,296✔
304
        AS.inputslock = dummylock;
1,296✔
305
        AS.outputslock = dummylock;
1,296✔
306
        AS.MaxExprSizeLock = dummylock;
1,296✔
307
        AP.PreVarLock = dummylock;
1,296✔
308
        AC.halfmodlock = dummylock;
1,296✔
309
        MakeThreadBuckets(number,0);
1,296✔
310
/*
311
        Now we wait for the workers to finish their startup.
312
        We don't want to initialize the sortbots yet and run the risk that 
313
        some of them may end up with a lower number than one of the workers.
314
*/
315
        MasterWaitAll();
1,296✔
316
#ifdef WITHSORTBOTS
317
        if ( numberofworkers > 2 ) {
1,296✔
318
                numberofsortbots = numberofworkers-2;
640✔
319
                for ( j = numberofworkers+1; j < 2*numberofworkers-1; j++ ) {
1,920✔
320
                        if ( pthread_create(&thethread,NULL,RunSortBot,(void *)(&dummy)) )
1,280✔
321
                                goto failure;
×
322
                }
323
        }
324
        else {
325
                numberofsortbots = 0;
656✔
326
        }
327
        MasterWaitAllSortBots();
1,296✔
328
        DefineSortBotTree();
1,296✔
329
#endif
330
        IniSortBlocks(number-1);
1,296✔
331
        AS.MasterSort = 0;
1,296✔
332
        AM.storefilelock = dummylock;
1,296✔
333
/*
334
MesPrint("AB = %x %x %x  %d",AB[0],AB[1],AB[2], identityofthreads);
335
*/
336
        return(0);
1,296✔
337
failure:
×
338
        MesPrint("Cannot start %d threads",number);
×
339
        Terminate(-1);
×
340
        return(-1);
×
341
}
342

343
/*
344
          #] StartAllThreads : 
345
          #[ InitializeOneThread :
346
*/
347
/**
348
 *        Array for putting a label on memory allocations and error messages.
349
 */
350
UBYTE *scratchname[] = { (UBYTE *)"scratchsize",
351
                         (UBYTE *)"scratchsize",
352
                         (UBYTE *)"hidesize" };
353
/**
354
 *        Initializes one thread. This includes the allocation of its private
355
 *        space and all its buffers. Also the initialization of variables.
356
 *
357
 *        @param identity The (TFORM defined) integer identifier of the thread.
358
 *        @return A pointer to the struct with all private data of the thread.
359
 *        We call this struct B and we have a system of macros
360
 *        (defined in variable.h) that allows us to access its substructs in
361
 *        the same way as the corresponding substructs in sequential FORM are
362
 *        accessed. Example:
363
 *                In TFORM  AR is defined as B->R
364
 *                In FORM   AR is defined as A.R  (here it is part of the A struct)
365
 *
366
 *        One complication:
367
 *                AM.ScratSize can be rather big. We don't want all the workers
368
 *                to have an allocation of that size. Some computers may run out
369
 *                of allocations.
370
 *                We need on the workers:
371
 *                        AR.Fscr[0] : input for keep brackets and expressions in rhs
372
 *                        AR.Fscr[1] : output of the sorting to be fed to the master
373
 *                        AR.Fscr[2] : input for keep brackets and expressions in rhs
374
 *                Hence the 0 and 2 channels can use a rather small buffer like
375
 *                        10*AM.MaxTer.
376
 *                The 1 channel needs a buffer roughly AM.ScratSize/#ofworkers.
377
 */
378

379
ALLPRIVATES *InitializeOneThread(int identity)
6,416✔
380
{
381
        WORD *t, *ScratchBuf;
6,416✔
382
        int i, j, bsize, *bp;
6,416✔
383
        LONG ScratchSize[3], IOsize;
6,416✔
384
        ALLPRIVATES *B;
6,416✔
385
        UBYTE *s;
6,416✔
386

387
        wakeup[identity] = 0;
6,416✔
388
        wakeuplocks[identity] = dummylock;
6,416✔
389
        pthread_condattr_init(&(wakeupconditionattributes[identity]));
6,416✔
390
        pthread_condattr_setpshared(&(wakeupconditionattributes[identity]),PTHREAD_PROCESS_PRIVATE);
6,416✔
391
        wakeupconditions[identity] = dummywakeupcondition;
6,416✔
392
        pthread_cond_init(&(wakeupconditions[identity]),&(wakeupconditionattributes[identity]));
6,416✔
393
        wakeupmasterthread[identity] = 0;
6,416✔
394
        wakeupmasterthreadlocks[identity] = dummylock;
6,416✔
395
        wakeupmasterthreadconditions[identity] = dummywakeupcondition;
6,416✔
396

397
        bsize = sizeof(ALLPRIVATES);
6,416✔
398
        bsize = (bsize+sizeof(int)-1)/sizeof(int);
6,416✔
399
        B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
6,416✔
400
        for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
38,200,864✔
401

402
        AB[identity] = B;
6,416✔
403
/*
404
                        12-jun-2007 JV:
405
        For the timing one has to know a few things:
406
        The POSIX standard is that there is only a single process ID and that
407
        getrusage returns the time of all the threads together.
408
        Under Linux there are two methods though: The older LinuxThreads and NPTL.
409
        LinuxThreads gives each thread its own process id. This makes that we
410
        can time the threads with getrusage, and hence this was done. Under NPTL
411
        this has been 'corrected' and suddenly getruage doesn't work anymore the
412
        way it used to. Now we need
413
                clock_gettime(CLOCK_THREAD_CPUTIME_ID,&timing)
414
        which is declared in <time.h> and we need -lrt extra in the link statement.
415
        (this is at least the case on blade02 at DESY-Zeuthen).
416
        See also the code in tools.c at the routine Timer.
417
        We may still have to include more stuff there.
418
*/
419
        if ( identity > 0 ) TimeCPU(0);
6,416✔
420

421
#ifdef WITHSORTBOTS
422

423
        if ( identity > numberofworkers ) {
6,416✔
424
/*
425
                Some workspace is needed when we have a PolyFun and we have to add
426
                two terms and the new result is going to be longer than the old result.
427
*/
428
                LONG length = AM.WorkSize*sizeof(WORD)/8+AM.MaxTer*2;
1,280✔
429
                AT.WorkSpace = (WORD *)Malloc1(length,"WorkSpace");
1,280✔
430
                AT.WorkTop = AT.WorkSpace + length/sizeof(WORD);
1,280✔
431
                AT.WorkPointer = AT.WorkSpace;
1,280✔
432
                AT.identity = identity;
1,280✔
433
/*
434
                The SB struct gets treated in IniSortBlocks.
435
                The SortBotIn variables will be defined DefineSortBotTree.
436
*/
437
                if ( AN.SoScratC == 0 ) {
1,280✔
438
                        AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
1,280✔
439
                }
440
                AT.SS = (SORTING *)Malloc1(sizeof(SORTING),"dummy sort buffer");
1,280✔
441
                AT.SS->PolyFlag = 0;
1,280✔
442

443
                AT.comsym[0] = 8;
1,280✔
444
                AT.comsym[1] = SYMBOL;
1,280✔
445
                AT.comsym[2] = 4;
1,280✔
446
                AT.comsym[3] = 0;
1,280✔
447
                AT.comsym[4] = 1;
1,280✔
448
                AT.comsym[5] = 1;
1,280✔
449
                AT.comsym[6] = 1;
1,280✔
450
                AT.comsym[7] = 3;
1,280✔
451
                AT.comnum[0] = 4;
1,280✔
452
                AT.comnum[1] = 1;
1,280✔
453
                AT.comnum[2] = 1;
1,280✔
454
                AT.comnum[3] = 3;
1,280✔
455
                AT.comfun[0] = FUNHEAD+4;
1,280✔
456
                AT.comfun[1] = FUNCTION;
1,280✔
457
                AT.comfun[2] = FUNHEAD;
1,280✔
458
                AT.comfun[3] = 0;
1,280✔
459
#if FUNHEAD > 3
460
                for ( i = 4; i <= FUNHEAD; i++ )
461
                        AT.comfun[i] = 0;
462
#endif
463
                AT.comfun[FUNHEAD+1] = 1;
1,280✔
464
                AT.comfun[FUNHEAD+2] = 1;
1,280✔
465
                AT.comfun[FUNHEAD+3] = 3;
1,280✔
466
                AT.comind[0] = 7;
1,280✔
467
                AT.comind[1] = INDEX;
1,280✔
468
                AT.comind[2] = 3;
1,280✔
469
                AT.comind[3] = 0;
1,280✔
470
                AT.comind[4] = 1;
1,280✔
471
                AT.comind[5] = 1;
1,280✔
472
                AT.comind[6] = 3;
1,280✔
473

474
                AT.inprimelist = -1;
1,280✔
475
                AT.sizeprimelist = 0;
1,280✔
476
                AT.primelist = 0;
1,280✔
477
                AT.bracketinfo = 0;
1,280✔
478
                
479
                AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
1,280✔
480

481
                AR.sLevel = 0;
1,280✔
482
                AR.wranfia = 0;
1,280✔
483
                AR.wranfcall = 0;
1,280✔
484
                AR.wranfnpair1 = NPAIR1;
1,280✔
485
                AR.wranfnpair2 = NPAIR2;
1,280✔
486
                AN.NumFunSorts = 5;
1,280✔
487
                AN.MaxFunSorts = 5;
1,280✔
488
                AN.SplitScratch = 0;
1,280✔
489
                AN.SplitScratchSize = AN.InScratch = 0;
1,280✔
490
                AN.SplitScratch1 = 0;
1,280✔
491
                AN.SplitScratchSize1 = AN.InScratch1 = 0;
1,280✔
492

493
                AN.FunSorts = (SORTING **)Malloc1((AN.NumFunSorts+1)*sizeof(SORTING *),"FunSort pointers");
1,280✔
494
                for ( i = 0; i <= AN.NumFunSorts; i++ ) AN.FunSorts[i] = 0;
8,960✔
495
                AN.FunSorts[0] = AT.S0 = AT.SS;
1,280✔
496
                AN.idfunctionflag = 0;
1,280✔
497
                AN.tryterm = 0;
1,280✔
498

499
                return(B);
1,280✔
500
        }
501
        if ( identity == 0 && AN.SoScratC == 0 ) {
5,136✔
502
                AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
1,296✔
503
        }
504
#endif
505
        AR.CurDum = AM.IndDum;
5,136✔
506
        for ( j = 0; j < 3; j++ ) {
20,544✔
507
                if ( identity == 0 ) {
15,408✔
508
                        if ( j == 2 ) {
3,888✔
509
                                ScratchSize[j] = AM.HideSize;
1,296✔
510
                        }
511
                        else {
512
                                ScratchSize[j] = AM.ScratSize;
2,592✔
513
                        }
514
                        if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
3,888✔
515
                }
516
                else {
517
/*
518
                        ScratchSize[j] = AM.ScratSize / (numberofthreads-1);
519
                        ScratchSize[j] = ScratchSize[j] / 20;
520
                        if ( ScratchSize[j] < 10*AM.MaxTer ) ScratchSize[j] = 10 * AM.MaxTer;
521
*/
522
                        if ( j == 1 ) ScratchSize[j] = AM.ThreadScratOutSize;
11,520✔
523
                        else          ScratchSize[j] = AM.ThreadScratSize;
7,680✔
524
                        if ( ScratchSize[j] < 4*AM.MaxTer ) ScratchSize[j] = 4 * AM.MaxTer;
11,520✔
525
                        AR.Fscr[j].name = 0;
11,520✔
526
                }
527
                ScratchSize[j] = ( ScratchSize[j] + 255 ) / 256;
15,408✔
528
                ScratchSize[j] = ScratchSize[j] * 256;
15,408✔
529
                ScratchBuf = (WORD *)Malloc1(ScratchSize[j]*sizeof(WORD),(char *)(scratchname[j]));
15,408✔
530
                AR.Fscr[j].POsize = ScratchSize[j] * sizeof(WORD);
15,408✔
531
                AR.Fscr[j].POfull = AR.Fscr[j].POfill = AR.Fscr[j].PObuffer = ScratchBuf;
15,408✔
532
                AR.Fscr[j].POstop = AR.Fscr[j].PObuffer + ScratchSize[j];
15,408✔
533
                PUTZERO(AR.Fscr[j].POposition);
15,408✔
534
                AR.Fscr[j].pthreadslock = dummylock;
15,408✔
535
                AR.Fscr[j].wPOsize = AR.Fscr[j].POsize;
15,408✔
536
                AR.Fscr[j].wPObuffer = AR.Fscr[j].PObuffer;
15,408✔
537
                AR.Fscr[j].wPOfill = AR.Fscr[j].POfill;
15,408✔
538
                AR.Fscr[j].wPOfull = AR.Fscr[j].POfull;
15,408✔
539
                AR.Fscr[j].wPOstop = AR.Fscr[j].POstop;
15,408✔
540
        }
541
        AR.InInBuf = 0;
5,136✔
542
        AR.InHiBuf = 0;
5,136✔
543
        AR.Fscr[0].handle = -1;
5,136✔
544
        AR.Fscr[1].handle = -1;
5,136✔
545
        AR.Fscr[2].handle = -1;
5,136✔
546
        AR.FoStage4[0].handle = -1;
5,136✔
547
        AR.FoStage4[1].handle = -1;
5,136✔
548
        IOsize = AM.S0->file.POsize;
5,136✔
549
#ifdef WITHZLIB
550
        AR.FoStage4[0].ziosize = IOsize;
5,136✔
551
        AR.FoStage4[1].ziosize = IOsize;
5,136✔
552
        AR.FoStage4[0].ziobuffer = 0;
5,136✔
553
        AR.FoStage4[1].ziobuffer = 0;
5,136✔
554
#endif        
555
        AR.FoStage4[0].POsize  = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
5,136✔
556
        AR.FoStage4[1].POsize  = ((IOsize+sizeof(WORD)-1)/sizeof(WORD))*sizeof(WORD);
5,136✔
557

558
        AR.hidefile = &(AR.Fscr[2]);
5,136✔
559
        AR.StoreData.Handle = -1;
5,136✔
560
        AR.SortType = AC.SortType;
5,136✔
561

562
        AN.IndDum = AM.IndDum;
5,136✔
563

564
        if ( identity > 0 ) {
5,136✔
565
                s = (UBYTE *)(FG.fname); i = 0;
3,840✔
566
                while ( *s ) { s++; i++; }
72,960✔
567
                s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[0] file");
3,840✔
568
                snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
3,840✔
569
                s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '0';
3,840✔
570
                AR.Fscr[0].name = (char *)s;
3,840✔
571
                s = (UBYTE *)(FG.fname); i = 0;
3,840✔
572
                while ( *s ) { s++; i++; }
72,960✔
573
                s = (UBYTE *)Malloc1(sizeof(char)*(i+12),"name for Fscr[1] file");
3,840✔
574
                snprintf((char *)s,i+12,"%s.%d",FG.fname,identity);
3,840✔
575
                s[i-3] = 's'; s[i-2] = 'c'; s[i-1] = '1';
3,840✔
576
                AR.Fscr[1].name = (char *)s;
3,840✔
577
        }
578

579
        AR.CompressBuffer = (WORD *)Malloc1((AM.CompressSize+10)*sizeof(WORD),"compresssize");
5,136✔
580
        AR.ComprTop = AR.CompressBuffer + AM.CompressSize;
5,136✔
581
        AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
5,136✔
582
/*
583
        Here we make all allocations for the struct AT
584
        (which is AB[identity].T or B->T with B = AB+identity).
585
*/
586
        AT.WorkSpace = (WORD *)Malloc1(AM.WorkSize*sizeof(WORD),"WorkSpace");
5,136✔
587
        AT.WorkTop = AT.WorkSpace + AM.WorkSize;
5,136✔
588
        AT.WorkPointer = AT.WorkSpace;
5,136✔
589

590
        AT.Nest = (NESTING)Malloc1((LONG)sizeof(struct NeStInG)*AM.maxFlevels,"functionlevels");
5,136✔
591
        AT.NestStop = AT.Nest + AM.maxFlevels;
5,136✔
592
        AT.NestPoin = AT.Nest;
5,136✔
593

594
        AT.WildMask = (WORD *)Malloc1((LONG)AM.MaxWildcards*sizeof(WORD),"maxwildcards");
5,136✔
595

596
        LOCK(availabilitylock);
5,136✔
597
        AT.ebufnum = inicbufs();                /* Buffer for extras during execution */
5,136✔
598
        AT.fbufnum = inicbufs();                /* Buffer for caching in factorization */
5,136✔
599
        AT.allbufnum = inicbufs();                /* Buffer for id,all */
5,136✔
600
        AT.aebufnum = inicbufs();                /* Buffer for id,all */
5,136✔
601
        UNLOCK(availabilitylock);
5,136✔
602

603
        AT.RepCount = (int *)Malloc1((LONG)((AM.RepMax+3)*sizeof(int)),"repeat buffers");
5,136✔
604
        AN.RepPoint = AT.RepCount;
5,136✔
605
        AN.polysortflag = 0;
5,136✔
606
        AN.subsubveto = 0;
5,136✔
607
        AN.tryterm = 0;
5,136✔
608
        AT.RepTop = AT.RepCount + AM.RepMax;
5,136✔
609

610
        AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
5,136✔
611
                                ,"argument list names");
612
        AT.WildcardBufferSize = AC.WildcardBufferSize;
5,136✔
613
        AT.previousEfactor = 0;
5,136✔
614

615
        AT.identity = identity;
5,136✔
616
        AT.LoadBalancing = 0;
5,136✔
617
/*
618
        Still to do: the SS stuff.
619
                     the Fscr[3]
620
                     the FoStage4[2]
621
*/
622
        if ( AT.WorkSpace == 0 ||
5,136✔
623
             AT.Nest == 0 ||
5,136✔
624
             AT.WildMask == 0 ||
5,136✔
625
             AT.RepCount == 0 ||
5,136✔
626
             AT.WildArgTaken == 0 ) goto OnError;
×
627
/*
628
        And initializations
629
*/
630
        AT.comsym[0] = 8;
5,136✔
631
        AT.comsym[1] = SYMBOL;
5,136✔
632
        AT.comsym[2] = 4;
5,136✔
633
        AT.comsym[3] = 0;
5,136✔
634
        AT.comsym[4] = 1;
5,136✔
635
        AT.comsym[5] = 1;
5,136✔
636
        AT.comsym[6] = 1;
5,136✔
637
        AT.comsym[7] = 3;
5,136✔
638
        AT.comnum[0] = 4;
5,136✔
639
        AT.comnum[1] = 1;
5,136✔
640
        AT.comnum[2] = 1;
5,136✔
641
        AT.comnum[3] = 3;
5,136✔
642
        AT.comfun[0] = FUNHEAD+4;
5,136✔
643
        AT.comfun[1] = FUNCTION;
5,136✔
644
        AT.comfun[2] = FUNHEAD;
5,136✔
645
        AT.comfun[3] = 0;
5,136✔
646
#if FUNHEAD > 3
647
        for ( i = 4; i <= FUNHEAD; i++ )
648
                AT.comfun[i] = 0;
649
#endif
650
        AT.comfun[FUNHEAD+1] = 1;
5,136✔
651
        AT.comfun[FUNHEAD+2] = 1;
5,136✔
652
        AT.comfun[FUNHEAD+3] = 3;
5,136✔
653
        AT.comind[0] = 7;
5,136✔
654
        AT.comind[1] = INDEX;
5,136✔
655
        AT.comind[2] = 3;
5,136✔
656
        AT.comind[3] = 0;
5,136✔
657
        AT.comind[4] = 1;
5,136✔
658
        AT.comind[5] = 1;
5,136✔
659
        AT.comind[6] = 3;
5,136✔
660
        AT.locwildvalue[0] = SUBEXPRESSION;
5,136✔
661
        AT.locwildvalue[1] = SUBEXPSIZE;
5,136✔
662
        for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
20,544✔
663
        AT.mulpat[0] = TYPEMULT;
5,136✔
664
        AT.mulpat[1] = SUBEXPSIZE+3;
5,136✔
665
        AT.mulpat[2] = 0;
5,136✔
666
        AT.mulpat[3] = SUBEXPRESSION;
5,136✔
667
        AT.mulpat[4] = SUBEXPSIZE;
5,136✔
668
        AT.mulpat[5] = 0;
5,136✔
669
        AT.mulpat[6] = 1;
5,136✔
670
        for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
20,544✔
671
        AT.proexp[0] = SUBEXPSIZE+4;
5,136✔
672
        AT.proexp[1] = EXPRESSION;
5,136✔
673
        AT.proexp[2] = SUBEXPSIZE;
5,136✔
674
        AT.proexp[3] = -1;
5,136✔
675
        AT.proexp[4] = 1;
5,136✔
676
        for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
10,272✔
677
        AT.proexp[SUBEXPSIZE+1] = 1;
5,136✔
678
        AT.proexp[SUBEXPSIZE+2] = 1;
5,136✔
679
        AT.proexp[SUBEXPSIZE+3] = 3;
5,136✔
680
        AT.proexp[SUBEXPSIZE+4] = 0;
5,136✔
681
        AT.dummysubexp[0] = SUBEXPRESSION;
5,136✔
682
        AT.dummysubexp[1] = SUBEXPSIZE+4;
5,136✔
683
        for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
20,544✔
684
        AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
5,136✔
685
        AT.dummysubexp[SUBEXPSIZE+1] = 4;
5,136✔
686
        AT.dummysubexp[SUBEXPSIZE+2] = 0;
5,136✔
687
        AT.dummysubexp[SUBEXPSIZE+3] = 0;
5,136✔
688

689
        AT.MinVecArg[0] = 7+ARGHEAD;
5,136✔
690
        AT.MinVecArg[ARGHEAD] = 7;
5,136✔
691
        AT.MinVecArg[1+ARGHEAD] = INDEX;
5,136✔
692
        AT.MinVecArg[2+ARGHEAD] = 3;
5,136✔
693
        AT.MinVecArg[3+ARGHEAD] = 0;
5,136✔
694
        AT.MinVecArg[4+ARGHEAD] = 1;
5,136✔
695
        AT.MinVecArg[5+ARGHEAD] = 1;
5,136✔
696
        AT.MinVecArg[6+ARGHEAD] = -3;
5,136✔
697
        t = AT.FunArg;
5,136✔
698
        *t++ = 4+ARGHEAD+FUNHEAD;
5,136✔
699
        for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
10,272✔
700
        *t++ = 4+FUNHEAD;
5,136✔
701
        *t++ = 0;
5,136✔
702
        *t++ = FUNHEAD;
5,136✔
703
        for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
10,272✔
704
        *t++ = 1; *t++ = 1; *t++ = 3;
5,136✔
705

706
        AT.inprimelist = -1;
5,136✔
707
        AT.sizeprimelist = 0;
5,136✔
708
        AT.primelist = 0;
5,136✔
709
        AT.nfac = AT.nBer = 0;
5,136✔
710
        AT.factorials = 0;
5,136✔
711
        AT.bernoullis = 0;
5,136✔
712
        AR.wranfia = 0;
5,136✔
713
        AR.wranfcall = 0;
5,136✔
714
        AR.wranfnpair1 = NPAIR1;
5,136✔
715
        AR.wranfnpair2 = NPAIR2;
5,136✔
716
        AR.wranfseed = 0;
5,136✔
717
        AN.SplitScratch = 0;
5,136✔
718
        AN.SplitScratchSize = AN.InScratch = 0;
5,136✔
719
        AN.SplitScratch1 = 0;
5,136✔
720
        AN.SplitScratchSize1 = AN.InScratch1 = 0;
5,136✔
721
/*
722
        Now the sort buffers. They depend on which thread. The master
723
        inherits the sortbuffer from AM.S0
724
*/
725
        if ( identity == 0 ) {
5,136✔
726
                AT.S0 = AM.S0;
1,296✔
727
        }
728
        else {
729
/*
730
                For the moment we don't have special settings.
731
                They may become costly in virtual memory.
732
*/
733
                AT.S0 = AllocSort(AM.S0->LargeSize*sizeof(WORD)/numberofworkers
3,840✔
734
                                                 ,AM.S0->SmallSize*sizeof(WORD)/numberofworkers
3,840✔
735
                                                 ,AM.S0->SmallEsize*sizeof(WORD)/numberofworkers
3,840✔
736
                                                 ,AM.S0->TermsInSmall
737
                                                 ,AM.S0->MaxPatches
738
/*                                                 ,AM.S0->MaxPatches/numberofworkers  */
739
                                                 ,AM.S0->MaxFpatches/numberofworkers
3,840✔
740
                                                 ,AM.S0->file.POsize
3,840✔
741
                                                 ,0);
742
        }
743
        AR.CompressPointer = AR.CompressBuffer;
5,136✔
744
/*
745
        Install the store caches (15-aug-2006 JV)
746
*/
747
        AT.StoreCache = AT.StoreCacheAlloc = 0;
5,136✔
748
        if ( AM.NumStoreCaches > 0 ) {
5,136✔
749
                STORECACHE sa, sb;
5,136✔
750
                LONG size;
5,136✔
751
                size = sizeof(struct StOrEcAcHe)+AM.SizeStoreCache;
5,136✔
752
                size = ((size-1)/sizeof(size_t)+1)*sizeof(size_t);
5,136✔
753
                AT.StoreCacheAlloc = (STORECACHE)Malloc1(size*AM.NumStoreCaches,"StoreCaches");
5,136✔
754
                sa = AT.StoreCache = AT.StoreCacheAlloc;
5,136✔
755
                for ( i = 0; i < AM.NumStoreCaches; i++ ) {
25,680✔
756
                        sb = (STORECACHE)(void *)((UBYTE *)sa+size);
20,544✔
757
                        if ( i == AM.NumStoreCaches-1 ) {
20,544✔
758
                                sa->next = 0;
5,136✔
759
                        }
760
                        else {
761
                                sa->next = sb;
15,408✔
762
                        }
763
                        SETBASEPOSITION(sa->position,-1);
20,544✔
764
                        SETBASEPOSITION(sa->toppos,-1);
20,544✔
765
                        sa = sb;
20,544✔
766
                }                
767
        }
768

769
        ReserveTempFiles(2);
5,136✔
770
        return(B);
5,136✔
771
OnError:;
×
772
        MLOCK(ErrorMessageLock);
×
773
        MesPrint("Error initializing thread %d",identity);
×
774
        MUNLOCK(ErrorMessageLock);
×
775
        Terminate(-1);
×
776
        return(B);
×
777
}
778

779
/*
780
          #] InitializeOneThread : 
781
          #[ FinalizeOneThread :
782
*/
783
/**
784
 *        To be called at the end of the run to give the final time statistics for
785
 *        this thread.
786
 *
787
 *        @param identity The TFORM defined integer identity of the thread.
788
 *                        In principle we could find it out from here with a call
789
 *                        to WhoAmI but because this is to be called at a very
790
 *                        late stage during clean up, we don't want to run any risks.
791
 */
792

793
void FinalizeOneThread(int identity)
4,592✔
794
{
795
        timerinfo[identity] = TimeCPU(1);
4,592✔
796
}
4,592✔
797

798
/*
799
          #] FinalizeOneThread : 
800
          #[ ClearAllThreads :
801
*/
802
/**
803
 *        To be called at the end of running TFORM.
804
 *        Theoretically the system can clean up after up, but it may be better
805
 *        to do it ourselves.
806
 */
807

NEW
808
void ClearAllThreads(void)
×
809
{
810
        int i;
×
811
        MasterWaitAll();
×
812
        for ( i = 1; i <= numberofworkers; i++ ) {
×
813
                WakeupThread(i,CLEARCLOCK);
×
814
        }
815
#ifdef WITHSORTBOTS
816
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
×
817
                WakeupThread(i,CLEARCLOCK);
×
818
        }
819
#endif
820
}
×
821

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

832
void TerminateAllThreads(void)
1,164✔
833
{
834
        int i;
1,164✔
835
        for ( i = 1; i <= numberofworkers; i++ ) {
4,608✔
836
                GetThread(i);
3,444✔
837
                WakeupThread(i,TERMINATETHREAD);
3,444✔
838
        }
839
#ifdef WITHSORTBOTS
840
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
2,312✔
841
                WakeupThread(i,TERMINATETHREAD);
1,148✔
842
        }
843
#endif
844
        for ( i = 1; i <= numberofworkers; i++ ) {
4,608✔
845
                pthread_join(threadpointers[i],NULL);
3,444✔
846
        }
847
#ifdef WITHSORTBOTS
848
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
2,312✔
849
                pthread_join(threadpointers[i],NULL);
1,148✔
850
        }
851
#endif
852
}
1,164✔
853

854
/*
855
          #] TerminateAllThreads : 
856
          #[ MakeThreadBuckets :
857
*/
858
/**
859
 *        Creates 2*number thread buckets. We want double the number because
860
 *        we want to prepare number of them while another number are occupied.
861
 *
862
 *        Each bucket should have about AC.ThreadBucketSize*AM.MaxTerm words.
863
 *
864
 *        When loading a thread we only have to pass the address of a full bucket.
865
 *        This gives more overlap between the master and the workers and hence
866
 *        less waiting.
867
 *
868
 *        The buckets are used because sending terms one by one to the workers
869
 *        costs too much overhead. Hence we put a number of terms in each bucket
870
 *        and then pass the whole bucket. In the ideal case the master loads the
871
 *        buckets while the workers are processing the contents of the buckets
872
 *        they have been assigned. In practise often the processing can go faster
873
 *        than that the master can fill the buckets for all workers.
874
 *        It should be possible to improve this bucket system, but the trivial
875
 *        idea 
876
 *
877
 *        @param number The number of workers
878
 *        @param par    par = 0: First allocation
879
 *                      par = 1: Reallocation when we change the bucket size with the 
880
 *                               threadbucketsize statement.
881
 */
882

883
int MakeThreadBuckets(int number, int par)
1,296✔
884
{
885
        int i;
1,296✔
886
        LONG sizethreadbuckets;
1,296✔
887
        THREADBUCKET *thr;
1,296✔
888
/*
889
        First we need a decent estimate. Not all terms should be maximal.
890
        Note that AM.MaxTer is in bytes!!!
891
        Maybe we should try to limit the size here a bit more effectively.
892
        This is a great consumer of memory.
893
*/
894
        sizethreadbuckets = ( AC.ThreadBucketSize + 1 ) * AM.MaxTer + 2*sizeof(WORD);
1,296✔
895
        if ( AC.ThreadBucketSize >= 250 )      sizethreadbuckets /= 4;
1,296✔
896
        else if ( AC.ThreadBucketSize >= 90 )  sizethreadbuckets /= 3;
8✔
897
        else if ( AC.ThreadBucketSize >= 40 )  sizethreadbuckets /= 2;
8✔
898
        sizethreadbuckets /= sizeof(WORD);
1,296✔
899
        
900
        if ( par == 0 ) {
1,296✔
901
                numthreadbuckets = 2*(number-1);
1,296✔
902
                threadbuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
1,296✔
903
                freebuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
1,296✔
904
        }
905
        if ( par > 0 ) {
1,296✔
906
                if ( sizethreadbuckets <= threadbuckets[0]->threadbuffersize ) return(0);
×
907
                for ( i = 0; i < numthreadbuckets; i++ ) {
×
908
                        thr = threadbuckets[i];
×
909
                        M_free(thr->deferbuffer,"deferbuffer");
×
910
                }
911
        }
912
        else {
913
                for ( i = 0; i < numthreadbuckets; i++ ) {
8,976✔
914
                        threadbuckets[i] = (THREADBUCKET *)Malloc1(sizeof(THREADBUCKET),"threadbuckets");
7,680✔
915
                        threadbuckets[i]->lock = dummylock;
7,680✔
916
                }
917
        }
918
        for ( i = 0; i < numthreadbuckets; i++ ) {
8,976✔
919
                thr = threadbuckets[i];
7,680✔
920
                thr->threadbuffersize = sizethreadbuckets;
7,680✔
921
                thr->free = BUCKETFREE;
7,680✔
922
                thr->deferbuffer = (POSITION *)Malloc1(2*sizethreadbuckets*sizeof(WORD)
15,360✔
923
                                        +(AC.ThreadBucketSize+1)*sizeof(POSITION),"deferbuffer");
7,680✔
924
                thr->threadbuffer = (WORD *)(thr->deferbuffer+AC.ThreadBucketSize+1);
7,680✔
925
                thr->compressbuffer = (WORD *)(thr->threadbuffer+sizethreadbuckets);
7,680✔
926
                thr->busy = BUCKETPREPARINGTERM;
7,680✔
927
                thr->usenum = thr->totnum = 0;
7,680✔
928
                thr->type = BUCKETDOINGTERMS;
7,680✔
929
        }
930
        return(0);
931
}
932

933
/*
934
          #] MakeThreadBuckets : 
935
          #[ GetTimerInfo :
936
*/
937

938
/**
939
 *  Returns a pointer to the static timerinfo together with information about
940
 *  its size. This is used by the checkpoint code to save this information in
941
 *  the recovery file.
942
 */
943
int GetTimerInfo(LONG** ti,LONG** sti)
×
944
{
945
        *ti = timerinfo;
×
946
        *sti = sumtimerinfo;
×
947
#ifdef WITHSORTBOTS
948
        return AM.totalnumberofthreads*2;
×
949
#else
950
        return AM.totalnumberofthreads;
951
#endif
952
}
953

954
/*
955
          #] GetTimerInfo : 
956
          #[ WriteTimerInfo :
957
*/
958

959
/**
960
 *  Writes data into the static timerinfo variable. This is used by the
961
 *  checkpoint code to restore the correct timings for the individual threads.
962
 */
963
void WriteTimerInfo(LONG* ti,LONG* sti)
×
964
{
965
        int i;
×
966
#ifdef WITHSORTBOTS
967
        int max = AM.totalnumberofthreads*2;
×
968
#else
969
        int max = AM.totalnumberofthreads;
970
#endif
971
        for ( i=0; i<max; ++i ) {
×
972
                timerinfo[i] = ti[i];
×
973
                sumtimerinfo[i] = sti[i];
×
974
        }
975
}
×
976

977
/*
978
          #] WriteTimerInfo : 
979
          #[ GetWorkerTimes :
980
*/
981
/**
982
 *        Gets the total CPU time of all workers together.
983
 *        To be called at the end of the TFORM run.
984
 */
985

986
LONG GetWorkerTimes(void)
2,880✔
987
{
988
        LONG retval = 0;
2,880✔
989
        int i;
2,880✔
990
        for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
11,448✔
991
#ifdef WITHSORTBOTS
992
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ )
5,736✔
993
                retval += timerinfo[i] + sumtimerinfo[i];
2,856✔
994
#endif
995
        return(retval);
2,880✔
996
}
997

998
/*
999
          #] GetWorkerTimes : 
1000
          #[ UpdateOneThread :
1001
*/
1002
/**
1003
 *        Fix up some of the things that happened at compiler time.
1004
 *
1005
 *        @param identity The TFORM defined integer thread identifier.
1006
 */
1007

1008
int UpdateOneThread(int identity)
11,652✔
1009
{
1010
        ALLPRIVATES *B = AB[identity], *B0 = AB[0];
11,652✔
1011
        AR.GetFile = AR0.GetFile;
11,652✔
1012
        AR.KeptInHold = AR0.KeptInHold;
11,652✔
1013
        AR.CurExpr = AR0.CurExpr;
11,652✔
1014
        AR.SortType = AC.SortType;
11,652✔
1015
        if ( AT.WildcardBufferSize < AC.WildcardBufferSize ) {
11,652✔
1016
                M_free(AT.WildArgTaken,"argument list names");
×
1017
                AT.WildcardBufferSize = AC.WildcardBufferSize;
×
1018
                AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
×
1019
                                ,"argument list names");
1020
                if ( AT.WildArgTaken == 0 ) return(-1);
×
1021
        }
1022
        return(0);
1023
}
1024

1025
/*
1026
          #] UpdateOneThread : 
1027
          #[ LoadOneThread :
1028
*/
1029
/**
1030
 *        Loads all relevant variables from thread 'from' into thread 'identity'
1031
 *        This is to be done just prior to waking up the thread.
1032
 *        It is important to keep the number of variables to be copied to a minimum
1033
 *        because this is part of the 'overhead'.
1034
 *
1035
 *        @param from     the source thread which has all the variables already
1036
 *        @param identity the TFORM defined integer thread identifier of the thread that needs the copy
1037
 *        @param thr      the bucket that contains the terms to be processed by 'identity'
1038
 *        @param par                if 1 copies the already active pieces in the (de)compress buffer
1039
 *        @return Standard return convention (OK -> 0)
1040
 */
1041

1042
int LoadOneThread(int from, int identity, THREADBUCKET *thr, int par)
326,552✔
1043
{
1044
        WORD *t1, *t2;
326,552✔
1045
        ALLPRIVATES *B = AB[identity], *B0 = AB[from];
326,552✔
1046

1047
        AR.DefPosition = AR0.DefPosition;
326,552✔
1048
        AR.NoCompress = AR0.NoCompress;
326,552✔
1049
        AR.gzipCompress = AR0.gzipCompress;
326,552✔
1050
        AR.BracketOn = AR0.BracketOn;
326,552✔
1051
        AR.CurDum = AR0.CurDum;
326,552✔
1052
        AR.DeferFlag = AR0.DeferFlag;
326,552✔
1053
        AR.TePos = 0;
326,552✔
1054
        AR.sLevel = AR0.sLevel;
326,552✔
1055
        AR.Stage4Name = AR0.Stage4Name;
326,552✔
1056
        AR.GetOneFile = AR0.GetOneFile;
326,552✔
1057
        AR.PolyFun = AR0.PolyFun;
326,552✔
1058
        AR.PolyFunInv = AR0.PolyFunInv;
326,552✔
1059
        AR.PolyFunType = AR0.PolyFunType;
326,552✔
1060
        AR.PolyFunExp = AR0.PolyFunExp;
326,552✔
1061
        AR.PolyFunVar = AR0.PolyFunVar;
326,552✔
1062
        AR.PolyFunPow = AR0.PolyFunPow;
326,552✔
1063
        AR.Eside = AR0.Eside;
326,552✔
1064
        AR.Cnumlhs = AR0.Cnumlhs;
326,552✔
1065
/*
1066
        AR.MaxBracket = AR0.MaxBracket;
1067

1068
        The compressbuffer contents are mainly relevant for keep brackets
1069
        We should do this only if there is a keep brackets statement
1070
        We may however still need the compressbuffer for expressions in the rhs.
1071
*/
1072
        if ( par >= 1 ) {
326,552✔
1073
/*
1074
                We may not need this %%%%% 7-apr-2006
1075
*/
1076
                t1 = AR.CompressBuffer; t2 = AR0.CompressBuffer;
×
1077
                while ( t2 < AR0.CompressPointer ) *t1++ = *t2++;
×
1078
                AR.CompressPointer = t1;
×
1079

1080
        }
1081
        else {
1082
                AR.CompressPointer = AR.CompressBuffer;
326,552✔
1083
        }
1084
        if ( AR.DeferFlag ) {
326,552✔
1085
                if ( AR.infile->handle < 0 ) {
126✔
1086
                        AR.infile->POfill = AR0.infile->POfill;
8✔
1087
                }
1088
                else {
1089
/*
1090
                        We have to set the value of POposition to something that will
1091
                        force a read in the first try.
1092
*/
1093
                        AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer;
118✔
1094
                }
1095
        }
1096
        if ( par == 0 ) {
326,552✔
1097
                AN.threadbuck = thr;
12,064✔
1098
                AN.ninterms = thr->firstterm;
12,064✔
1099
        }
1100
        else if ( par == 1 ) {
314,488✔
1101
                WORD *tstop;
×
1102
                t1 = thr->threadbuffer; tstop = t1 + *t1;
×
1103
                t2 = AT.WorkPointer;
×
1104
                while ( t1 < tstop ) *t2++ = *t1++;
×
1105
                AN.ninterms = thr->firstterm;
×
1106
        }
1107
        AN.TeInFun = 0;
326,552✔
1108
        AN.ncmod = AC.ncmod;
326,552✔
1109
        AT.BrackBuf = AT0.BrackBuf;
326,552✔
1110
        AT.bracketindexflag = AT0.bracketindexflag;
326,552✔
1111
        AN.PolyFunTodo = 0;
326,552✔
1112
/*
1113
        The relevant variables and the term are in their place.
1114
        There is nothing more to do.
1115
*/
1116
        return(0);
326,552✔
1117
}
1118

1119
/*
1120
          #] LoadOneThread : 
1121
          #[ BalanceRunThread :
1122
*/
1123
/**
1124
 *        To start a thread from the Generator routine we need to pass a number
1125
 *        of variables.
1126
 *        This is part of the second stage load balancing. The second stage is
1127
 *        when we interfere with the expansion tree in Generator and let branches
1128
 *        of the tree be treated by other workers.
1129
 *        Early experiments show disappointing results and hence the system is
1130
 *        currently disabled.
1131
 *
1132
 *        @param identity  The identity of the thread that will receive the term.
1133
 *        @param term      The term to be passed to thread 'identity'
1134
 *        @param level     The level at which we are in the tree. Defines the statement.
1135
 *        @return Standard return convention (OK -> 0)
1136
 */
1137

1138
int BalanceRunThread(PHEAD int identity, WORD *term, WORD level)
×
1139
{
1140
        GETBIDENTITY
1141
        ALLPRIVATES *BB;
×
1142
        WORD *t, *tt;
×
1143
        int i, *ti, *tti;
×
1144

1145
        LoadOneThread(AT.identity,identity,0,2);
×
1146
/*
1147
        Extra loading if needed. Quantities changed in Generator.
1148
        Like the level that has to be passed.
1149
*/
1150
        BB = AB[identity];
×
1151
        BB->R.level = level;
×
1152
        BB->T.TMbuff = AT.TMbuff;
×
1153
        ti = AT.RepCount; tti = BB->T.RepCount;
×
1154
        i = AN.RepPoint - AT.RepCount;
×
1155
        BB->N.RepPoint = BB->T.RepCount + i;
×
1156
        for ( ; i >= 0; i-- ) tti[i] = ti[i];
×
1157

1158
        t = term; i = *term;
×
1159
        tt = BB->T.WorkSpace;
×
1160
        NCOPY(tt,t,i);
×
1161
        BB->T.WorkPointer = tt;
×
1162

1163
        WakeupThread(identity,HIGHERLEVELGENERATION);
×
1164

1165
        return(0);
×
1166
}
1167

1168
/*
1169
          #] BalanceRunThread : 
1170
          #[ SetWorkerFiles :
1171
*/
1172
/**
1173
 *        Initializes the scratch files at the start of the execution of a module.
1174
 */
1175

1176
void SetWorkerFiles(void)
4,584✔
1177
{
1178
        int id;
4,584✔
1179
        ALLPRIVATES *B, *B0 = AB[0];
4,584✔
1180
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
18,336✔
1181
                B = AB[id];
13,752✔
1182
                AR.infile = &(AR.Fscr[0]);
13,752✔
1183
                AR.outfile = &(AR.Fscr[1]);
13,752✔
1184
                AR.hidefile = &(AR.Fscr[2]);
13,752✔
1185
                AR.infile->handle = AR0.infile->handle;
13,752✔
1186
                AR.hidefile->handle = AR0.hidefile->handle;
13,752✔
1187
                if ( AR.infile->handle < 0 ) {
13,752✔
1188
                        AR.infile->PObuffer = AR0.infile->PObuffer;
13,680✔
1189
                        AR.infile->POstop = AR0.infile->POstop;
13,680✔
1190
                        AR.infile->POfill = AR0.infile->POfill;
13,680✔
1191
                        AR.infile->POfull = AR0.infile->POfull;
13,680✔
1192
                        AR.infile->POsize = AR0.infile->POsize;
13,680✔
1193
                        AR.InInBuf = AR0.InInBuf;
13,680✔
1194
                        AR.infile->POposition = AR0.infile->POposition;
13,680✔
1195
                        AR.infile->filesize = AR0.infile->filesize;
13,680✔
1196
                }
1197
                else {
1198
                        AR.infile->PObuffer = AR.infile->wPObuffer;
72✔
1199
                        AR.infile->POstop = AR.infile->wPOstop;
72✔
1200
                        AR.infile->POfill = AR.infile->wPOfill;
72✔
1201
                        AR.infile->POfull = AR.infile->wPOfull;
72✔
1202
                        AR.infile->POsize = AR.infile->wPOsize;
72✔
1203
                        AR.InInBuf = 0;
72✔
1204
                        PUTZERO(AR.infile->POposition);
72✔
1205
                }
1206
/*
1207
                If there is some writing, it betters happens to ones own outfile.
1208
                Currently this is to be done only for InParallel.
1209
                Merging of the outputs is then done by the CopyExpression routine.
1210
*/
1211
                {
1212
                        AR.outfile->PObuffer = AR.outfile->wPObuffer;
13,752✔
1213
                        AR.outfile->POstop = AR.outfile->wPOstop;
13,752✔
1214
                        AR.outfile->POfill = AR.outfile->wPOfill;
13,752✔
1215
                        AR.outfile->POfull = AR.outfile->wPOfull;
13,752✔
1216
                        AR.outfile->POsize = AR.outfile->wPOsize;
13,752✔
1217
                        PUTZERO(AR.outfile->POposition);
13,752✔
1218
                }
1219
                if ( AR.hidefile->handle < 0 ) {
13,752✔
1220
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
13,752✔
1221
                        AR.hidefile->POstop = AR0.hidefile->POstop;
13,752✔
1222
                        AR.hidefile->POfill = AR0.hidefile->POfill;
13,752✔
1223
                        AR.hidefile->POfull = AR0.hidefile->POfull;
13,752✔
1224
                        AR.hidefile->POsize = AR0.hidefile->POsize;
13,752✔
1225
                        AR.InHiBuf = AR0.InHiBuf;
13,752✔
1226
                        AR.hidefile->POposition = AR0.hidefile->POposition;
13,752✔
1227
                        AR.hidefile->filesize = AR0.hidefile->filesize;
13,752✔
1228
                }
1229
                else {
1230
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
1231
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
1232
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
1233
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
1234
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
1235
                        AR.InHiBuf = 0;
×
1236
                        PUTZERO(AR.hidefile->POposition);
×
1237
                }
1238
        }
1239
        if ( AR0.StoreData.dirtyflag ) {
4,584✔
1240
                for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
×
1241
                        B = AB[id];
×
1242
                        AR.StoreData = AR0.StoreData;
×
1243
                }
1244
        }
1245
}
4,584✔
1246

1247
/*
1248
          #] SetWorkerFiles : 
1249
          #[ RunThread :
1250
*/
1251
/**
1252
 *        This is the routine that represents each worker.
1253
 *        The model is that the worker waits for a 'signal'.
1254
 *        If there is a signal it wakes up, looks at what signal and then takes
1255
 *        the corresponding action. After this it goes back to sleep.
1256
 */
1257

1258
void *RunThread(void *dummy)
3,840✔
1259
{
1260
        WORD *term, *ttin, *tt, *ttco, *oldwork;
3,840✔
1261
        int identity, wakeupsignal, identityretv, i, tobereleased, errorcode;
3,840✔
1262
        ALLPRIVATES *B;
3,840✔
1263
        THREADBUCKET *thr;
3,840✔
1264
        POSITION *ppdef;
3,840✔
1265
        EXPRESSIONS e;
3,840✔
1266
        DUMMYUSE(dummy);
3,840✔
1267
        identity = SetIdentity(&identityretv);
3,840✔
1268
        threadpointers[identity] = pthread_self();
3,840✔
1269
        B = InitializeOneThread(identity);
3,840✔
1270
        while ( ( wakeupsignal = ThreadWait(identity) ) > 0 ) {
364,963✔
1271
                switch ( wakeupsignal ) {
361,211✔
1272
/*
1273
                        #[ STARTNEWEXPRESSION :
1274
*/
1275
                        case STARTNEWEXPRESSION:
11,652✔
1276
/*
1277
                                Set up the sort routines etc.
1278
                                Start with getting some buffers synchronized with the compiler
1279
*/
1280
                                if ( UpdateOneThread(identity) ) {
11,652✔
1281
                                        MLOCK(ErrorMessageLock);
×
1282
                                        MesPrint("Update error in starting expression in thread %d in module %d",identity,AC.CModule);
×
1283
                                        MUNLOCK(ErrorMessageLock);
×
1284
                                        Terminate(-1);
×
1285
                                }
1286
                                AR.DeferFlag = AC.ComDefer;
11,652✔
1287
                                AR.sLevel = AS.sLevel;
11,652✔
1288
                                AR.MaxDum = AM.IndDum;
11,652✔
1289
                                AR.expchanged = AB[0]->R.expchanged;
11,652✔
1290
                                AR.expflags = AB[0]->R.expflags;
11,652✔
1291
                                AR.PolyFun = AB[0]->R.PolyFun;
11,652✔
1292
                                AR.PolyFunInv = AB[0]->R.PolyFunInv;
11,652✔
1293
                                AR.PolyFunType = AB[0]->R.PolyFunType;
11,652✔
1294
                                AR.PolyFunExp = AB[0]->R.PolyFunExp;
11,652✔
1295
                                AR.PolyFunVar = AB[0]->R.PolyFunVar;
11,652✔
1296
                                AR.PolyFunPow = AB[0]->R.PolyFunPow;
11,652✔
1297
/*
1298
                                Now fire up the sort buffer.
1299
*/
1300
                                NewSort(BHEAD0);
11,652✔
1301
                                break;
11,652✔
1302
/*
1303
                        #] STARTNEWEXPRESSION : 
1304
                        #[ LOWESTLEVELGENERATION :
1305
*/
1306
                        case LOWESTLEVELGENERATION:
11,958✔
1307
#ifdef INNERTEST
1308
                                if ( AC.InnerTest ) {
1309
                                        if ( StrCmp(AC.TestValue,(UBYTE *)INNERTEST) == 0 ) {
1310
                                                MesPrint("Testing(Worker%d): value = %s",AT.identity,AC.TestValue);
1311
                                        }
1312
                                }
1313
#endif
1314
                                e = Expressions + AR.CurExpr;
11,958✔
1315
                                thr = AN.threadbuck;
11,958✔
1316
                                ppdef = thr->deferbuffer;
11,958✔
1317
                                ttin = thr->threadbuffer;
11,958✔
1318
                                ttco = thr->compressbuffer;
11,958✔
1319
                                term = AT.WorkPointer;
11,958✔
1320
                                thr->usenum = 0;
11,958✔
1321
                                tobereleased = 0;
11,958✔
1322
                                AN.inputnumber = thr->firstterm;
11,958✔
1323
                                AN.ninterms = thr->firstterm;
11,958✔
1324
                                do {
695,948✔
1325
                                  thr->usenum++;        /* For if the master wants to steal the bucket */
695,948✔
1326
                                  tt = term; i = *ttin;
695,948✔
1327
                                  NCOPY(tt,ttin,i);
29,928,368✔
1328
                                  AT.WorkPointer = tt;
695,948✔
1329
                                  if ( AR.DeferFlag ) {
695,948✔
1330
                                        tt = AR.CompressBuffer; i = *ttco;
412✔
1331
                                        NCOPY(tt,ttco,i);
13,440✔
1332
                                        AR.CompressPointer = tt;
412✔
1333
                                        AR.DefPosition = ppdef[0]; ppdef++;
412✔
1334
                                  }
1335
                                  if ( thr->free == BUCKETTERMINATED ) {
695,948✔
1336
/*
1337
                                    The next statement allows the master to steal the bucket
1338
                                    for load balancing purposes. We do still execute the current
1339
                                        term, but afterwards we drop out.
1340
                                        Once we have written the release code, we cannot use this
1341
                                        bucket anymore. Hence the exit to the label bucketstolen.
1342
*/
1343
                                        if ( thr->usenum == thr->totnum ) {
×
1344
                                                thr->free = BUCKETCOMINGFREE;
×
1345
                                        }
1346
                                        else {
1347
                                                thr->free = BUCKETRELEASED;
×
1348
                                                tobereleased = 1;
×
1349
                                        }
1350
                                  }
1351
/*
1352
                                        What if we want to steal and we set thr->free while
1353
                                        the thread is inside the next code for a long time?
1354
                                  if ( AT.LoadBalancing ) {
1355
*/
1356
                                        LOCK(thr->lock);
695,948✔
1357
                                        thr->busy = BUCKETDOINGTERM;
695,948✔
1358
                                        UNLOCK(thr->lock);
695,948✔
1359
/*
1360
                                  }
1361
                                  else {
1362
                                        thr->busy = BUCKETDOINGTERM;
1363
                                  }
1364
*/
1365
                                  AN.RepPoint = AT.RepCount + 1;
695,948✔
1366

1367
                                  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
695,948✔
1368
                                    StoreTerm(BHEAD term);
×
1369
                                  }
1370
                                  else {
1371
                                  if ( AR.DeferFlag ) {
695,948✔
1372
                                        AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
412✔
1373
                                  }
1374
                                  else {
1375
                                        AN.IndDum = AM.IndDum;
695,536✔
1376
                                        AR.CurDum = ReNumber(BHEAD term);
695,536✔
1377
                                  }
1378
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
695,948✔
1379
                                  if ( AN.ncmod ) {
695,948✔
1380
                                        if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
4✔
1381
                                        else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
4✔
1382
                                  }
1383
                                  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
695,944✔
1384
                                  if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
695,948✔
1385
                                        MLOCK(ErrorMessageLock);
×
1386
                                        MesPrint("Thread %w executing term:");
×
1387
                                        PrintTerm(term,"LLG");
×
1388
                                        MUNLOCK(ErrorMessageLock);
×
1389
                                  }
1390
                                  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
695,948✔
1391
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
4,552✔
1392
                                                PolyFunClean(BHEAD term);
4,552✔
1393
                                  }
1394
                                  if ( Generator(BHEAD term,0) ) {
695,948✔
1395
                                        LowerSortLevel();
8✔
1396
                                        MLOCK(ErrorMessageLock);
8✔
1397
                                        MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
8✔
1398
                                        MUNLOCK(ErrorMessageLock);
8✔
1399
                                        Terminate(-1);
8✔
1400
                                  }
1401
                                  AN.ninterms++;
695,872✔
1402
                                  }
1403
/*                                  if ( AT.LoadBalancing ) { */
1404
                                        LOCK(thr->lock);
695,872✔
1405
                                        thr->busy = BUCKETPREPARINGTERM;
695,872✔
1406
                                        UNLOCK(thr->lock);
695,872✔
1407
/*
1408
                                  }
1409
                                  else {
1410
                                        thr->busy = BUCKETPREPARINGTERM;
1411
                                  }
1412
*/
1413
                                  if ( thr->free == BUCKETTERMINATED ) {
695,872✔
1414
                                        if ( thr->usenum == thr->totnum ) {
189✔
1415
                                                thr->free = BUCKETCOMINGFREE;
×
1416
                                        }
1417
                                        else {
1418
                                                thr->free = BUCKETRELEASED;
189✔
1419
                                                tobereleased = 1;
189✔
1420
                                        }
1421
                                  }
1422
                                  if ( tobereleased ) goto bucketstolen;
695,872✔
1423
                                } while ( *ttin );
695,683✔
1424
                                thr->free = BUCKETCOMINGFREE;
11,693✔
1425
bucketstolen:;
11,882✔
1426
/*                                if ( AT.LoadBalancing ) { */
1427
                                        LOCK(thr->lock);
11,882✔
1428
                                        thr->busy = BUCKETTOBERELEASED;
11,882✔
1429
                                        UNLOCK(thr->lock);
11,882✔
1430
/*                                }
1431
                                else {
1432
                                        thr->busy = BUCKETTOBERELEASED;
1433
                                }
1434
*/
1435
                                AT.WorkPointer = term;
11,882✔
1436
                                break;
11,882✔
1437
/*
1438
                        #] LOWESTLEVELGENERATION : 
1439
                        #[ FINISHEXPRESSION :
1440
*/
1441
#ifdef WITHSORTBOTS
1442
                        case CLAIMOUTPUT:
×
1443
                                LOCK(AT.SB.MasterBlockLock[1]);
×
1444
                                break;
×
1445
#endif
1446
                        case FINISHEXPRESSION:
11,424✔
1447
/*
1448
                                Finish the sort
1449

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

1561
                                When a thread has to do a complete (not too big) expression.
1562
                                The number of the expression to be done is in AR.exprtodo.
1563
                                The code is mostly taken from Processor. The only difference
1564
                                is with what to do with the output.
1565
                                The output should go to the scratch buffer of the worker
1566
                                (which is free at the right moment). If this buffer is too
1567
                                small we have a problem. We could write to file or give the
1568
                                master what we have and from now on the master has to collect
1569
                                pieces until things are complete.
1570
                                Note: this assumes that the expressions don't keep their order.
1571
                                If they have to keep their order, don't use this feature.
1572
*/
1573
                        case DOONEEXPRESSION: {
314,488✔
1574

1575
                                POSITION position, outposition;
314,488✔
1576
                                FILEHANDLE *fi, *fout, *oldoutfile;
314,488✔
1577
                                LONG dd = 0;
314,488✔
1578
                                WORD oldBracketOn = AR.BracketOn;
314,488✔
1579
                                WORD *oldBrackBuf = AT.BrackBuf;
314,488✔
1580
                                WORD oldbracketindexflag = AT.bracketindexflag;
314,488✔
1581
                                WORD fromspectator = 0;
314,488✔
1582
                                e = Expressions + AR.exprtodo;
314,488✔
1583
                                i = AR.exprtodo;
314,488✔
1584
                                AR.CurExpr = i;
314,488✔
1585
                                AR.SortType = AC.SortType;
314,488✔
1586
                                AR.expchanged = 0;
314,488✔
1587
                                if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
314,488✔
1588
                                        AR.BracketOn = 1;
×
1589
                                        AT.BrackBuf = AM.BracketFactors;
×
1590
                                        AT.bracketindexflag = 1;
×
1591
                                }
1592

1593
                                position = AS.OldOnFile[i];
314,488✔
1594
                                if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION ) {
314,488✔
1595
                                        AR.GetFile = 2; fi = AR.hidefile;
×
1596
                                }
1597
                                else {
1598
                                        AR.GetFile = 0; fi = AR.infile;
314,488✔
1599
                                }
1600
/*
1601
                                PUTZERO(fi->POposition);
1602
                                if ( fi->handle >= 0 ) {
1603
                                        fi->POfill = fi->POfull = fi->PObuffer;
1604
                                }
1605
*/
1606
                                SetScratch(fi,&position);
314,488✔
1607
                                term = oldwork = AT.WorkPointer;
314,488✔
1608
                                AR.CompressPointer = AR.CompressBuffer;
314,488✔
1609
                                AR.CompressPointer[0] = 0;
314,488✔
1610
                                AR.KeptInHold = 0;
314,488✔
1611
                                if ( GetTerm(BHEAD term) <= 0 ) {
314,488✔
1612
                                        MLOCK(ErrorMessageLock);
×
1613
                                        MesPrint("Expression %d has problems in scratchfile (t)",i);
×
1614
                                        MUNLOCK(ErrorMessageLock);
×
1615
                                        Terminate(-1);
×
1616
                                }
1617
                                if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
314,488✔
1618
                                term[3] = i;
314,488✔
1619
                                if ( term[5] < 0 ) {
314,488✔
1620
                                        fromspectator = -term[5];
×
1621
                                        PUTZERO(AM.SpectatorFiles[fromspectator-1].readpos);
×
1622
                                        term[5] = AC.cbufnum;
×
1623
                                }
1624
                                PUTZERO(outposition);
314,488✔
1625
                                fout = AR.outfile;
314,488✔
1626
                                fout->POfill = fout->POfull = fout->PObuffer;
314,488✔
1627
                                fout->POposition = outposition;
314,488✔
1628
                                if ( fout->handle >= 0 ) {
314,488✔
1629
                                        fout->POposition = outposition;
×
1630
                                }
1631
/*
1632
                                The next statement is needed because we need the system
1633
                                to believe that the expression is at position zero for
1634
                                the moment. In this worker, with no memory of other expressions,
1635
                                it is. This is needed for when a bracket index is made
1636
                                because there e->onfile is an offset. Afterwards, when the
1637
                                expression is written to its final location in the masters
1638
                                output e->onfile will get its real value.
1639
*/
1640
                                PUTZERO(e->onfile);
314,488✔
1641
                                if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) goto ProcErr;
314,488✔
1642

1643
                                AR.DeferFlag = AC.ComDefer;
314,488✔
1644

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

1762
                                if ( fout->handle >= 0 ) {        /* Now get rid of the file */
314,488✔
1763
                                        CloseFile(fout->handle);
×
1764
                                        fout->handle = -1;
×
1765
                                        remove(fout->name);
×
1766
                                        PUTZERO(fout->POposition);
×
1767
                                        PUTZERO(fout->filesize);
×
1768
                                        fout->POfill = fout->POfull = fout->PObuffer;
×
1769
                                }
1770
                                UpdateMaxSize();
314,488✔
1771

1772
                                AT.WorkPointer = oldwork;
314,488✔
1773

1774
                                } break;
314,488✔
1775
/*
1776
                        #] DOONEEXPRESSION : 
1777
                        #[ DOBRACKETS :
1778

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

1859
                        The program only comes here after a .clear
1860
*/
1861
                        case CLEARCLOCK:
×
1862
/*                                LOCK(clearclocklock); */
1863
                                sumtimerinfo[identity] += TimeCPU(1);
×
1864
                                timerinfo[identity] = TimeCPU(0);
×
1865
/*                                UNLOCK(clearclocklock); */
1866
                                break;
×
1867
/*
1868
                        #] CLEARCLOCK : 
1869
                        #[ MCTSEXPANDTREE :
1870
*/
1871
                        case MCTSEXPANDTREE:
111✔
1872
                                AT.optimtimes = AB[0]->T.optimtimes;
111✔
1873
                                find_Horner_MCTS_expand_tree();
111✔
1874
                                break;
111✔
1875
/*
1876
                        #] MCTSEXPANDTREE : 
1877
                        #[ OPTIMIZEEXPRESSION :
1878
*/
1879
                        case OPTIMIZEEXPRESSION:
60✔
1880
                                optimize_expression_given_Horner();
60✔
1881
                                break;
60✔
1882
/*
1883
                        #] OPTIMIZEEXPRESSION : 
1884
*/
1885
                        default:
×
1886
                                MLOCK(ErrorMessageLock);
×
1887
                                MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
×
1888
                                MUNLOCK(ErrorMessageLock);
×
1889
                                Terminate(-1);
×
1890
                                break;
×
1891
                }
1892
                /* we need the following update in case we are using checkpoints. then we
1893
                   need to readjust the clocks when recovering using this information */
1894
                timerinfo[identity] = TimeCPU(1);
361,123✔
1895
        }
1896
EndOfThread:;
3,444✔
1897
/*
1898
        This is the end of the thread. We cleanup and exit.
1899
        If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
1900
*/
1901
#ifdef WITHFLINT
1902
        flint_final_cleanup_thread();
1,722✔
1903
#endif
1904
        FinalizeOneThread(identity);
3,444✔
1905
        return(0);
3,444✔
1906
ProcErr:
×
1907
        Terminate(-1);
×
1908
        return(0);
×
1909
}
1910

1911
/*
1912
          #] RunThread : 
1913
          #[ RunSortBot :
1914
*/
1915
/**
1916
 *        This is the routine that represents each sortbot.
1917
 *        The model is that the sortbot waits for a 'signal'.
1918
 *        If there is a signal it wakes up, looks at what signal and then takes
1919
 *        the corresponding action. After this it goes back to sleep.
1920
 */
1921

1922
#ifdef WITHSORTBOTS
1923

1924
void *RunSortBot(void *dummy)
1,280✔
1925
{
1926
        int identity, wakeupsignal, identityretv;
1,280✔
1927
        ALLPRIVATES *B, *BB;
1,280✔
1928
        DUMMYUSE(dummy);
1,280✔
1929
        identity = SetIdentity(&identityretv);
1,280✔
1930
        threadpointers[identity] = pthread_self();
1,280✔
1931
        B = InitializeOneThread(identity);
1,280✔
1932
        while ( ( wakeupsignal = SortBotWait(identity) ) > 0 ) {
8,892✔
1933
                switch ( wakeupsignal ) {
7,616✔
1934
/*
1935
                        #[ INISORTBOT :
1936
*/
1937
                        case INISORTBOT:
3,808✔
1938
                                AR.CompressBuffer = AB[0]->R.CompressBuffer;
3,808✔
1939
                                AR.ComprTop = AB[0]->R.ComprTop;
3,808✔
1940
                                AR.CompressPointer = AB[0]->R.CompressPointer;
3,808✔
1941
                                AR.CurExpr = AB[0]->R.CurExpr;
3,808✔
1942
                                AR.PolyFun = AB[0]->R.PolyFun;
3,808✔
1943
                                AR.PolyFunInv = AB[0]->R.PolyFunInv;
3,808✔
1944
                                AR.PolyFunType = AB[0]->R.PolyFunType;
3,808✔
1945
                                AR.PolyFunExp = AB[0]->R.PolyFunExp;
3,808✔
1946
                                AR.PolyFunVar = AB[0]->R.PolyFunVar;
3,808✔
1947
                                AR.PolyFunPow = AB[0]->R.PolyFunPow;
3,808✔
1948
                                AR.SortType = AC.SortType;
3,808✔
1949
                                if ( AR.PolyFun == 0 ) { AT.SS->PolyFlag = 0; }
3,808✔
1950
                                else if ( AR.PolyFunType == 1 ) { AT.SS->PolyFlag = 1; }
300✔
1951
                                else if ( AR.PolyFunType == 2 ) {
276✔
1952
                                        if ( AR.PolyFunExp == 2
276✔
1953
                                          || AR.PolyFunExp == 3 ) AT.SS->PolyFlag = 1;
276✔
1954
                                        else                      AT.SS->PolyFlag = 2;
200✔
1955
                                }
1956
                                AT.SS->PolyWise = 0;
3,808✔
1957
                                AN.ncmod = AC.ncmod;
3,808✔
1958
                                LOCK(AT.SB.MasterBlockLock[1]);
3,808✔
1959
                                BB = AB[AT.SortBotIn1];
3,808✔
1960
                                LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
3,808✔
1961
                                BB = AB[AT.SortBotIn2];
3,808✔
1962
                                LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
3,808✔
1963
                                AT.SB.FillBlock = 1;
3,808✔
1964
                                AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
3,808✔
1965
                                SETBASEPOSITION(AN.theposition,0);
3,808✔
1966
                                break;
3,808✔
1967
/*
1968
                        #] INISORTBOT : 
1969
                        #[ RUNSORTBOT :
1970
*/
1971
                        case RUNSORTBOT:
3,808✔
1972
                                SortBotMerge(B);
3,808✔
1973
                                break;
3,808✔
1974
/*
1975
                        #] RUNSORTBOT : 
1976
                        #[ TERMINATETHREAD :
1977
*/
1978
                        case TERMINATETHREAD:
×
1979
                                goto EndOfThread;
×
1980
/*
1981
                        #] TERMINATETHREAD : 
1982
                        #[ CLEARCLOCK :
1983

1984
                        The program only comes here after a .clear
1985
*/
1986
                        case CLEARCLOCK:
×
1987
/*                                LOCK(clearclocklock); */
1988
                                sumtimerinfo[identity] += TimeCPU(1);
×
1989
                                timerinfo[identity] = TimeCPU(0);
×
1990
/*                                UNLOCK(clearclocklock); */
1991
                                break;
×
1992
/*
1993
                        #] CLEARCLOCK : 
1994
*/
1995
                        default:
×
1996
                                MLOCK(ErrorMessageLock);
×
1997
                                MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
×
1998
                                MUNLOCK(ErrorMessageLock);
×
1999
                                Terminate(-1);
×
2000
                                break;
×
2001
                }
2002
        }
2003
EndOfThread:;
1,148✔
2004
/*
2005
        This is the end of the thread. We cleanup and exit.
2006
        If we are using flint, call the per-thread cleanup function. This keep valgrind happy.
2007
*/
2008
#ifdef WITHFLINT
2009
        flint_final_cleanup_thread();
574✔
2010
#endif
2011
        FinalizeOneThread(identity);
1,148✔
2012
        return(0);
1,148✔
2013
}
2014

2015
#endif
2016

2017
/*
2018
          #] RunSortBot : 
2019
          #[ IAmAvailable :
2020
*/
2021
/**
2022
 *        To be called by a thread when it becomes available.
2023
 *        Puts it on a stack.
2024
 *        We use a stack model. It is also possible to define a circular queue.
2025
 *        This will be tried out at a later stage.
2026
 *        One advantage of a stack could be that if we cannot feed all threads
2027
 *        more sorting is done at the threads and the master has to do less.
2028
 *
2029
 *        @param identity The identity thread that signals its availability.
2030
 */
2031

2032
void IAmAvailable(int identity)
×
2033
{
2034
        int top;
×
2035
        LOCK(availabilitylock);
×
2036
        top = topofavailables;
×
2037
        listofavailables[topofavailables++] = identity;
×
2038
        if ( top == 0 ) {
×
2039
                UNLOCK(availabilitylock);
×
2040
                LOCK(wakeupmasterlock);
×
2041
                wakeupmaster = identity;
×
2042
                pthread_cond_signal(&wakeupmasterconditions);
×
2043
                UNLOCK(wakeupmasterlock);
×
2044
        }
2045
        else {
2046
                UNLOCK(availabilitylock);
×
2047
        }
2048
}
×
2049

2050
/*
2051
          #] IAmAvailable : 
2052
          #[ GetAvailableThread :
2053
*/
2054
/**
2055
 *        Gets an available thread from the top of the stack.
2056
 *        Maybe a circular buffer model would work better. This would mean that
2057
 *        we take the lowest available worker, rather than the highest.
2058
 *        We then have to work with high water marks and low water marks.
2059
 *        (writing point and reading point). Still to be investigated.
2060
 */
2061

2062
int GetAvailableThread(void)
545,240✔
2063
{
2064
        int retval = -1;
545,240✔
2065
        LOCK(availabilitylock);
545,240✔
2066
        if ( topofavailables > 0 ) retval = listofavailables[--topofavailables];
545,240✔
2067
        UNLOCK(availabilitylock);
545,240✔
2068
        if ( retval >= 0 ) {
545,240✔
2069
/*
2070
                Make sure the thread is indeed waiting and not between
2071
                saying that it is available and starting to wait.
2072
*/
2073
                LOCK(wakeuplocks[retval]);
326,723✔
2074
                UNLOCK(wakeuplocks[retval]);
326,723✔
2075
        }
2076
        return(retval);
545,240✔
2077
}
2078

2079
/*
2080
          #] GetAvailableThread : 
2081
          #[ ConditionalGetAvailableThread :
2082
*/
2083
/**
2084
 *        Looks whether a thread is available.
2085
 *        If a thread is available it is taken from the stack of available threads.
2086
 *
2087
 *        @return the identity of an available thread or -1 if none is available.
2088
 */
2089

NEW
2090
int ConditionalGetAvailableThread(void)
×
2091
{
2092
        int retval = -1;
×
2093
        if ( topofavailables > 0 ) {
×
2094
                LOCK(availabilitylock);
×
2095
                if ( topofavailables > 0 ) {
×
2096
                        retval = listofavailables[--topofavailables];
×
2097
                }
2098
                UNLOCK(availabilitylock);
×
2099
                if ( retval >= 0 ) {
×
2100
/*
2101
                        Make sure the thread is indeed waiting and not between
2102
                        saying that it is available and starting to wait.
2103
*/
2104
                        LOCK(wakeuplocks[retval]);
×
2105
                        UNLOCK(wakeuplocks[retval]);
×
2106
                }
2107
        }
2108
        return(retval);
×
2109
}
2110

2111
/*
2112
          #] ConditionalGetAvailableThread : 
2113
          #[ GetThread :
2114
*/
2115
/**
2116
 *        Gets a given thread from the list of available threads, even if
2117
 *        it isn't on the top of the stack.
2118
 *
2119
 *        @param identity The number of the thread that we want to remove from the
2120
 *                        list of available threads.
2121
 *        @return The number of the thread if it was available. -1 otherwise.
2122
 */
2123

2124
int GetThread(int identity)
26,280✔
2125
{
2126
        int retval = -1, j;
26,280✔
2127
        LOCK(availabilitylock);
26,280✔
2128
        for ( j = 0; j < topofavailables; j++ ) {
74,052✔
2129
                if ( identity == listofavailables[j] ) break;
47,772✔
2130
        }
2131
        if ( j < topofavailables ) {
26,280✔
2132
                --topofavailables;
26,280✔
2133
                for ( ; j < topofavailables; j++ ) {
35,704✔
2134
                        listofavailables[j] = listofavailables[j+1];
9,424✔
2135
                }
2136
                retval = identity;
2137
        }
2138
        UNLOCK(availabilitylock);
26,280✔
2139
        return(retval);
26,280✔
2140
}
2141

2142
/*
2143
          #] GetThread : 
2144
          #[ ThreadWait :
2145
*/
2146
/**
2147
 *        To be called by a thread when it has nothing to do.
2148
 *        It goes to sleep and waits for a wakeup call.
2149
 *        The return value is the number of the wakeup signal.
2150
 *
2151
 *        @param identity The number of the thread.
2152
 *        @return The number of the wake-up signal.
2153
 */
2154

2155
int ThreadWait(int identity)
364,963✔
2156
{
2157
        int retval, top, j;
364,963✔
2158
        LOCK(wakeuplocks[identity]);
364,963✔
2159
        LOCK(availabilitylock);
364,963✔
2160
        top = topofavailables;
364,963✔
2161
        for ( j = topofavailables; j > 0; j-- )
552,514✔
2162
                listofavailables[j] = listofavailables[j-1];
187,551✔
2163
        listofavailables[0] = identity;
364,963✔
2164
        topofavailables++;
364,963✔
2165
        if ( top == 0 || topofavailables == numberofworkers ) {
364,963✔
2166
                UNLOCK(availabilitylock);
291,536✔
2167
                LOCK(wakeupmasterlock);
291,536✔
2168
                wakeupmaster = identity;
291,536✔
2169
                pthread_cond_signal(&wakeupmasterconditions);
291,536✔
2170
                UNLOCK(wakeupmasterlock);
291,536✔
2171
        }
2172
        else {
2173
                UNLOCK(availabilitylock);
73,427✔
2174
        }
2175
        while ( wakeup[identity] == 0 ) {
729,618✔
2176
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
364,963✔
2177
        }
2178
        retval = wakeup[identity];
364,655✔
2179
        wakeup[identity] = 0;
364,655✔
2180
        UNLOCK(wakeuplocks[identity]);
364,655✔
2181
        return(retval);
364,655✔
2182
}
2183

2184
/*
2185
          #] ThreadWait : 
2186
          #[ SortBotWait :
2187
*/
2188
 
2189
#ifdef WITHSORTBOTS
2190
/**
2191
 *        To be called by a sortbot thread when it has nothing to do.
2192
 *        It goes to sleep and waits for a wakeup call.
2193
 *        The return value is the number of the wakeup signal.
2194
 *
2195
 *        @param identity The number of the sortbot thread.
2196
 *        @return The number of the wake-up signal.
2197
 */
2198

2199
int SortBotWait(int identity)
8,892✔
2200
{
2201
        int retval;
8,892✔
2202
        LOCK(wakeuplocks[identity]);
8,892✔
2203
        LOCK(availabilitylock);
8,892✔
2204
        topsortbotavailables++;
8,892✔
2205
        if ( topsortbotavailables >= numberofsortbots ) {
8,892✔
2206
                UNLOCK(availabilitylock);
4,446✔
2207
                LOCK(wakeupsortbotlock);
4,446✔
2208
                wakeupmaster = identity;
4,446✔
2209
                pthread_cond_signal(&wakeupsortbotconditions);
4,446✔
2210
                UNLOCK(wakeupsortbotlock);
4,446✔
2211
        }
2212
        else {
2213
                UNLOCK(availabilitylock);
4,446✔
2214
        }
2215
        while ( wakeup[identity] == 0 ) {
17,656✔
2216
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
8,892✔
2217
        }
2218
        retval = wakeup[identity];
8,764✔
2219
        wakeup[identity] = 0;
8,764✔
2220
        UNLOCK(wakeuplocks[identity]);
8,764✔
2221
        return(retval);
8,764✔
2222
}
2223

2224
#endif
2225

2226
/*
2227
          #] SortBotWait : 
2228
          #[ ThreadClaimedBlock :
2229
*/
2230
/**
2231
 *        When the final sort of an expression starts the workers have to claim
2232
 *        the first block in the buffers of the master for their output.
2233
 *        The master may only continue after all workers have claimed their block
2234
 *        because otherwise it is possible that the master may claim this block for
2235
 *        reading before it has been written in.
2236
 *        Hence the master must wait till all blocks have been claimed. Then the
2237
 *        master will get signalled that it can continue.
2238
 */
2239

2240
int ThreadClaimedBlock(int identity)
11,424✔
2241
{
2242
        LOCK(availabilitylock);
11,424✔
2243
        numberclaimed++;        
11,424✔
2244
        if ( numberclaimed >= numberofworkers ) {
11,424✔
2245
                UNLOCK(availabilitylock);
3,808✔
2246
                LOCK(wakeupmasterlock);
3,808✔
2247
                wakeupmaster = identity;
3,808✔
2248
                pthread_cond_signal(&wakeupmasterconditions);
3,808✔
2249
                UNLOCK(wakeupmasterlock);
3,808✔
2250
        }
2251
        else {
2252
                UNLOCK(availabilitylock);
7,616✔
2253
        }
2254
        return(0);
11,424✔
2255
}
2256

2257
/*
2258
          #] ThreadClaimedBlock : 
2259
          #[ MasterWait :
2260
*/
2261
/**
2262
 *        To be called by the master when it has to wait for one of the
2263
 *        workers to become available.
2264
 *        It goes to sleep and waits for a wakeupmaster call.
2265
 *        The return value is the identity of the process that wakes up the master.
2266
 */
2267

2268
int MasterWait(void)
219,082✔
2269
{
2270
        int retval;
219,082✔
2271
        LOCK(wakeupmasterlock);
219,082✔
2272
        while ( wakeupmaster == 0 ) {
416,659✔
2273
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
197,577✔
2274
        }
2275
        retval = wakeupmaster;
219,082✔
2276
        wakeupmaster = 0;
219,082✔
2277
        UNLOCK(wakeupmasterlock);
219,082✔
2278
        return(retval);
219,082✔
2279
}
2280

2281
/*
2282
          #] MasterWait : 
2283
          #[ MasterWaitThread :
2284
*/
2285
/**
2286
 *        To be called by the master when it has to wait for a specific one of the
2287
 *        workers to become available.
2288
 *        The return value is the value of the signal.
2289
 */
2290

2291
int MasterWaitThread(int identity)
×
2292
{
2293
        int retval;
×
2294
        LOCK(wakeupmasterthreadlocks[identity]);
×
2295
        while ( wakeupmasterthread[identity] == 0 ) {
×
2296
                pthread_cond_wait(&(wakeupmasterthreadconditions[identity])
×
2297
                                ,&(wakeupmasterthreadlocks[identity]));
2298
        }
2299
        retval = wakeupmasterthread[identity];
×
2300
        wakeupmasterthread[identity] = 0;
×
2301
        UNLOCK(wakeupmasterthreadlocks[identity]);
×
2302
        return(retval);
×
2303
}
2304

2305
/*
2306
          #] MasterWaitThread : 
2307
          #[ MasterWaitAll :
2308
*/
2309
/**
2310
 *        To be called by the master when it has to wait for all of the
2311
 *        workers to finish a given task.
2312
 *        It goes to sleep and waits for a wakeup call in ThreadWait
2313
 */
2314

2315
void MasterWaitAll(void)
17,000✔
2316
{
2317
        LOCK(wakeupmasterlock);
17,000✔
2318
        while ( topofavailables < numberofworkers ) {
31,737✔
2319
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
14,813✔
2320
        }
2321
        UNLOCK(wakeupmasterlock);
16,924✔
2322
        return;
16,924✔
2323
}
2324

2325
/*
2326
          #] MasterWaitAll : 
2327
          #[ MasterWaitAllSortBots :
2328
*/
2329
 
2330
#ifdef WITHSORTBOTS
2331

2332
/**
2333
 *        To be called by the master when it has to wait for all of the
2334
 *        sortbots to start their task.
2335
 */
2336

2337
void MasterWaitAllSortBots(void)
5,102✔
2338
{
2339
        LOCK(wakeupsortbotlock);
5,102✔
2340
        while ( topsortbotavailables < numberofsortbots ) {
7,648✔
2341
                pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
2,546✔
2342
        }
2343
        UNLOCK(wakeupsortbotlock);
5,102✔
2344
        return;
5,102✔
2345
}
2346

2347
#endif
2348

2349
/*
2350
          #] MasterWaitAllSortBots : 
2351
          #[ MasterWaitAllBlocks :
2352
*/
2353
/**
2354
 *        To be called by the master when it has to wait for all of the
2355
 *        workers to claim their first block in the sort buffers of the master.
2356
 *        It goes to sleep and waits for a wakeup call.
2357
 */
2358

2359
void MasterWaitAllBlocks(void)
3,808✔
2360
{
2361
        LOCK(wakeupmasterlock);
3,808✔
2362
        while ( numberclaimed < numberofworkers ) {
8,030✔
2363
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
4,222✔
2364
        }
2365
        UNLOCK(wakeupmasterlock);
3,808✔
2366
        return;
3,808✔
2367
}
2368

2369
/*
2370
          #] MasterWaitAllBlocks : 
2371
          #[ WakeupThread :
2372
*/
2373
/**
2374
 *        To be called when the indicated thread needs waking up.
2375
 *        The signal number should be nonzero!
2376
 *
2377
 *        @param identity     The number of the worker to be woken up
2378
 *        @param signalnumber The signal with which it should be woken up.
2379
 */
2380

2381
void WakeupThread(int identity, int signalnumber)
373,419✔
2382
{
2383
        if ( signalnumber == 0 ) {
373,419✔
2384
                MLOCK(ErrorMessageLock);
×
2385
                MesPrint("Illegal wakeup signal for thread %d",identity);
×
2386
                MUNLOCK(ErrorMessageLock);
×
2387
                Terminate(-1);
×
2388
        }
2389
        LOCK(wakeuplocks[identity]);
373,419✔
2390
        wakeup[identity] = signalnumber;
373,419✔
2391
        pthread_cond_signal(&(wakeupconditions[identity]));
373,419✔
2392
        UNLOCK(wakeuplocks[identity]);
373,419✔
2393
}
373,419✔
2394

2395
/*
2396
          #] WakeupThread : 
2397
          #[ WakeupMasterFromThread :
2398
*/
2399
/**
2400
 *        To be called when the indicated thread needs to wake up the master.
2401
 *        The signal number should be nonzero!
2402
 *
2403
 *        @param identity     The number of the worker who wakes up the master.
2404
 *        @param signalnumber The signal with which the master should be woken up.
2405
 */
2406

2407
void WakeupMasterFromThread(int identity, int signalnumber)
×
2408
{
2409
        if ( signalnumber == 0 ) {
×
2410
                MLOCK(ErrorMessageLock);
×
2411
                MesPrint("Illegal wakeup signal for master %d",identity);
×
2412
                MUNLOCK(ErrorMessageLock);
×
2413
                Terminate(-1);
×
2414
        }
2415
        LOCK(wakeupmasterthreadlocks[identity]);
×
2416
        wakeupmasterthread[identity] = signalnumber;
×
2417
        pthread_cond_signal(&(wakeupmasterthreadconditions[identity]));
×
2418
        UNLOCK(wakeupmasterthreadlocks[identity]);
×
2419
}
×
2420

2421
/*
2422
          #] WakeupMasterFromThread : 
2423
          #[ SendOneBucket :
2424
*/
2425
/**
2426
 *        To be called when there is a full bucket and an available thread
2427
 *        It prepares the thread and then wakes it up.
2428
 */
2429

2430
int SendOneBucket(int type)
331✔
2431
{
2432
        ALLPRIVATES *B0 = AB[0];
331✔
2433
        THREADBUCKET *thr = 0;
331✔
2434
        int j, k, id;
331✔
2435
        for ( j = 0; j < numthreadbuckets; j++ ) {
670✔
2436
                if ( threadbuckets[j]->free == BUCKETFILLED ) {
670✔
2437
                        thr = threadbuckets[j];
331✔
2438
                        for ( k = j+1; k < numthreadbuckets; k++ )
1,949✔
2439
                                threadbuckets[k-1] = threadbuckets[k];
1,618✔
2440
                        threadbuckets[numthreadbuckets-1] = thr;
331✔
2441
                        break;
331✔
2442
                }
2443
        }
2444
        AN0.ninterms++;
331✔
2445
        while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
331✔
2446
/*
2447
        Prepare the thread. Give it the term and variables.
2448
*/
2449
        LoadOneThread(0,id,thr,0);
331✔
2450
        thr->busy = BUCKETASSIGNED;
331✔
2451
        thr->free = BUCKETINUSE;
331✔
2452
        numberoffullbuckets--;
331✔
2453
/*
2454
        And signal the thread to run.
2455
        Form now on we may only interfere with this bucket
2456
        1: after it has been marked BUCKETCOMINGFREE
2457
        2: when thr->busy == BUCKETDOINGTERM and then only when protected by
2458
           thr->lock. This would be for load balancing.
2459
*/
2460
        WakeupThread(id,type);
331✔
2461
/*        AN0.ninterms += thr->ddterms; */
2462
        return(0);
331✔
2463
}
2464

2465
/*
2466
          #] SendOneBucket : 
2467
          #[ InParallelProcessor :
2468
*/
2469
/**
2470
 *        We divide the expressions marked by partodo over the workers.
2471
 *        The workers are responsible for writing their results into the buffers
2472
 *        of the master (output). This is to be controlled by locks.
2473
 *        The order of the expressions may get changed this way.
2474
 *
2475
 *        The InParallel statement allows the execution of complete expressions
2476
 *        in a single worker simultaneously. This is useful for when there are
2477
 *        many short expressions. This way we don't need the bottleneck of the
2478
 *        merging by the master. The complete sort for each expression is done
2479
 *        inside its own single worker. The bottleneck here is the writing of the
2480
 *        result into the scratch system. This is now done by the workers themselves.
2481
 *        Because each expression must be contiguous, the writing should be done
2482
 *        as quickly as possible and be protected by locks.
2483
 *
2484
 *        The implementation of this statement gave a significant increase in
2485
 *        efficiency in the running of the Multiple Zeta Values program.
2486
 */
2487

2488
int InParallelProcessor(void)
2,292✔
2489
{
2490
        GETIDENTITY
2,292✔
2491
        int i, id, retval = 0, num = 0;
2,292✔
2492
        EXPRESSIONS e;
2,292✔
2493
        if ( numberofworkers >= 2 ) {
2,292✔
2494
                SetWorkerFiles();
2,292✔
2495
                for ( i = 0; i < NumExpressions; i++ ) {
941,336✔
2496
                        e = Expressions+i;
936,752✔
2497
                        if ( e->partodo <= 0 ) continue;
936,752✔
2498
                        if ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION
314,488✔
2499
                        || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION
2500
                        || e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
×
2501
                        }
2502
                        else {
2503
                                e->partodo = 0;
×
2504
                                continue;
×
2505
                        }
2506
                        if ( e->counter == 0 ) { /* Expression with zero terms */
314,488✔
2507
                                e->partodo = 0;
×
2508
                                continue;
×
2509
                        }
2510
/*
2511
                        This expression should go to an idle worker
2512
*/
2513
                        while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
527,971✔
2514
                        LoadOneThread(0,id,0,-1);
314,488✔
2515
                        AB[id]->R.exprtodo = i;
314,488✔
2516
                        WakeupThread(id,DOONEEXPRESSION);
314,488✔
2517
                        num++;
314,488✔
2518
                }
2519
/*
2520
                Now we have to wait for all workers to finish
2521
*/
2522
                if ( num > 0 ) MasterWaitAll();
2,292✔
2523

2524
                if ( AC.CollectFun ) AR.DeferFlag = 0;
2,292✔
2525
        }
2526
        else {
2527
                for ( i = 0; i < NumExpressions; i++ ) {
×
2528
                        Expressions[i].partodo = 0;
×
2529
                }
2530
        }
2531
        return(retval);
2,292✔
2532
}
2533

2534
/*
2535
          #] InParallelProcessor : 
2536
          #[ ThreadsProcessor :
2537
*/
2538
/**
2539
 *        This routine takes the role of the central part of the Processor routine
2540
 *        in the file proces.c when multiple threads are available.
2541
 *        It deals with the expressions that are not marked in the InParallel
2542
 *        statement. These are usually the large expressions. It will divide
2543
 *        the terms of these expressions over the workers, using a bucket system
2544
 *        to reduce overhead (buckets are collections of a number of terms that
2545
 *        are transferred together).
2546
 *        At the end of the expression when all terms have been assigned and 
2547
 *        workers become available again, there is a load balancing system to
2548
 *        take terms from the buckets of workers that still have to do many terms
2549
 *        and give them to idle workers. This is called first level load balancing.
2550
 *
2551
 *        A new feature is that for expressions with a bracket index the terms
2552
 *        can be distributed in collections of complete brackets (12-nov-2009).
2553
 *
2554
 *        The routine is called for each expression separately by Processor.
2555
 *
2556
 *        @param e              The expression to be executed
2557
 *        @param LastExpression Indicates whether it is the last expression in which case
2558
 *                              in the end the input scratch file can be deleted before
2559
 *                              the output is written. This saves diskspace.
2560
 */
2561

2562
int ThreadsProcessor(EXPRESSIONS e, WORD LastExpression, WORD fromspectator)
3,884✔
2563
{
2564
        ALLPRIVATES *B0 = AB[0], *B = B0;
3,884✔
2565
        int id, oldgzipCompress, endofinput = 0, j, still, k, defcount = 0, bra = 0, first = 1;
3,884✔
2566
        LONG dd = 0, ddd, thrbufsiz, thrbufsiz0, thrbufsiz2, numbucket = 0, numpasses;
3,884✔
2567
        LONG num, i;
3,884✔
2568
        WORD *oldworkpointer = AT0.WorkPointer, *tt, *ttco = 0, *t1 = 0, ter, *tstop = 0, *t2;
3,884✔
2569
        THREADBUCKET *thr = 0;
3,884✔
2570
        FILEHANDLE *oldoutfile = AR0.outfile;
3,884✔
2571
        GETTERM GetTermP = &GetTerm;
3,884✔
2572
        POSITION eonfile = AS.OldOnFile[e-Expressions];
3,884✔
2573
        numberoffullbuckets = 0;
3,884✔
2574
/*
2575
        Start up all threads. The lock needs to be around the whole loop
2576
        to keep processes from terminating quickly and putting themselves
2577
        in the list of available threads again.
2578
*/
2579
        AM.tracebackflag = 1;
3,884✔
2580

2581
        AS.sLevel = AR0.sLevel;
3,884✔
2582
        LOCK(availabilitylock);
3,884✔
2583
        topofavailables = 0;
3,884✔
2584
        for ( id = 1; id <= numberofworkers; id++ ) {
15,536✔
2585
                WakeupThread(id,STARTNEWEXPRESSION);
11,652✔
2586
        }
2587
        UNLOCK(availabilitylock);
3,884✔
2588
        NewSort(BHEAD0);
3,884✔
2589
        AN0.ninterms = 1;
3,884✔
2590
/*
2591
        Now for redefine
2592
*/
2593
        if ( AC.numpfirstnum > 0 ) {
3,884✔
2594
                for ( j = 0; j < AC.numpfirstnum; j++ ) {
56✔
2595
                        AC.inputnumbers[j] = -1;
28✔
2596
                }
2597
        }
2598
        MasterWaitAll();
3,884✔
2599
/*
2600
        Determine a reasonable bucketsize.
2601
        This is based on the value of AC.ThreadBucketSize and the number
2602
        of terms. We want at least 5 buckets per worker at the moment.
2603
        Some research should show whether this is reasonable.
2604

2605
        The number of terms in the expression is in e->counter
2606
*/
2607
        thrbufsiz2 = thrbufsiz = AC.ThreadBucketSize-1;
3,884✔
2608
        if ( ( e->counter / ( numberofworkers * 5 ) ) < thrbufsiz ) {
3,884✔
2609
                thrbufsiz = e->counter / ( numberofworkers * 5 ) - 1;
3,846✔
2610
                if ( thrbufsiz < 0 ) thrbufsiz = 0;
3,846✔
2611
        }
2612
        thrbufsiz0 = thrbufsiz;
3,884✔
2613
        numpasses = 5; /* this is just for trying */
3,884✔
2614
        thrbufsiz = thrbufsiz0 / (2 << numpasses);
3,884✔
2615
/*
2616
        Mark all buckets as free and take the first.
2617
*/
2618
        for ( j = 0; j < numthreadbuckets; j++ )
27,188✔
2619
                threadbuckets[j]->free = BUCKETFREE;
23,304✔
2620
        thr = threadbuckets[0];
3,884✔
2621
/*
2622
          #[ Whole brackets :
2623

2624
        First we look whether we have to work with entire brackets
2625
        This is the case when there is a non-NULL address in e->bracketinfo.
2626
        Of course we shouldn't have interference from a collect or keep statement.
2627
*/
2628
#ifdef WHOLEBRACKETS
2629
        if ( e->bracketinfo && AC.CollectFun == 0 && AR0.DeferFlag == 0 ) {
3,884✔
2630
                FILEHANDLE *curfile;
44✔
2631
                int didone = 0;
44✔
2632
                LONG num, n;
44✔
2633
                AN0.expr = e;
44✔
2634
                for ( n = 0; n < e->bracketinfo->indexfill; n++ ) {
302✔
2635
                        num = TreatIndexEntry(B0,n);
258✔
2636
                        if ( num > 0 ) {
258✔
2637
                                didone = 1;
184✔
2638
/*
2639
                                This bracket can be sent off.
2640
                                1: Look for an empty bucket
2641
*/
2642
ReTry:;
184✔
2643
                                for ( j = 0; j < numthreadbuckets; j++ ) {
1,190✔
2644
                                        switch ( threadbuckets[j]->free ) {
1,112✔
2645
                                                case BUCKETFREE:
106✔
2646
                                                        thr = threadbuckets[j];
106✔
2647
                                                        goto Found1;
106✔
2648
                                                case BUCKETCOMINGFREE:
78✔
2649
                                                        thr = threadbuckets[j];
78✔
2650
                                                        thr->free = BUCKETFREE;
78✔
2651
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
441✔
2652
                                                                threadbuckets[k-1] = threadbuckets[k];
363✔
2653
                                                        threadbuckets[numthreadbuckets-1] = thr;
78✔
2654
                                                        j--;
78✔
2655
                                                        break;
78✔
2656
                                                default:
2657
                                                        break;
2658
                                        }
2659
                                }
2660
Found1:;
78✔
2661
                                if ( j < numthreadbuckets ) {
184✔
2662
/*
2663
                                        Found an empty bucket. Fill it.
2664
*/
2665
                                        thr->firstbracket = n;
106✔
2666
                                        thr->lastbracket = n + num - 1;
106✔
2667
                                        thr->type = BUCKETDOINGBRACKET;
106✔
2668
                                        thr->free = BUCKETFILLED;
106✔
2669
                                        thr->firstterm = AN0.ninterms;
106✔
2670
                                        for ( j = n; j < n+num; j++ ) {
474✔
2671
                                                AN0.ninterms += e->bracketinfo->indexbuffer[j].termsinbracket;
368✔
2672
                                        }
2673
                                        n += num-1;
106✔
2674
                                        numberoffullbuckets++;
106✔
2675
                                        if ( topofavailables > 0 ) {
106✔
2676
                                                SendOneBucket(DOBRACKETS);
16✔
2677
                                        }
2678
                                }
2679
/*
2680
                                        All buckets are in use.
2681
                                        Look/wait for an idle worker. Give it a bucket.
2682
                                        After that, retry for a bucket
2683
*/
2684
                                else {
2685
                                        while ( topofavailables <= 0 ) {
160✔
2686
                                                MasterWait();
82✔
2687
                                        }
2688
                                        SendOneBucket(DOBRACKETS);
78✔
2689
                                        goto ReTry;
78✔
2690
                                }
2691
                        }
2692
                }
2693
                if ( didone ) {
44✔
2694
/*
2695
                        And now put the input back in the original position.
2696
*/
2697
                        switch ( e->status ) {
6✔
2698
                                case UNHIDELEXPRESSION:
×
2699
                                case UNHIDEGEXPRESSION:
2700
                                case DROPHLEXPRESSION:
2701
                                case DROPHGEXPRESSION:
2702
                                case HIDDENLEXPRESSION:
2703
                                case HIDDENGEXPRESSION:
2704
                                        curfile = AR0.hidefile;
×
2705
                                        break;
×
2706
                                default:
6✔
2707
                                        curfile = AR0.infile;
6✔
2708
                                        break;
6✔
2709
                        }
2710
                        SetScratch(curfile,&eonfile);
6✔
2711
                        GetTerm(B0,AT0.WorkPointer);
6✔
2712
/*
2713
                        Now we point the GetTerm that is used to the one that is selective
2714
*/
2715
                        GetTermP = &GetTerm2;
6✔
2716
/*
2717
                        Next wait till there is a bucket available and initialize thr to it.
2718
*/
2719
                        for(;;) {
10✔
2720
                                for ( j = 0; j < numthreadbuckets; j++ ) {
58✔
2721
                                        switch ( threadbuckets[j]->free ) {
54✔
2722
                                                case BUCKETFREE:
6✔
2723
                                                        thr = threadbuckets[j];
6✔
2724
                                                        goto Found2;
6✔
2725
                                                case BUCKETCOMINGFREE:
4✔
2726
                                                        thr = threadbuckets[j];
4✔
2727
                                                        thr->free = BUCKETFREE;
4✔
2728
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
24✔
2729
                                                                threadbuckets[k-1] = threadbuckets[k];
20✔
2730
                                                        threadbuckets[numthreadbuckets-1] = thr;
4✔
2731
                                                        j--;
4✔
2732
                                                        break;
4✔
2733
                                                default:
2734
                                                        break;
2735
                                        }
2736
                                }
2737
                                while ( topofavailables <= 0 ) {
8✔
2738
                                        MasterWait();
4✔
2739
                                }
2740
                                while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
8✔
2741
                                        SendOneBucket(DOBRACKETS);
4✔
2742
                                }
2743
                        }
2744
Found2:;
6✔
2745
                        while ( numberoffullbuckets > 0 ) {
14✔
2746
                                while ( topofavailables <= 0 ) {
16✔
2747
                                        MasterWait();
8✔
2748
                                }
2749
                                while ( topofavailables > 0 && numberoffullbuckets > 0 ) {
16✔
2750
                                        SendOneBucket(DOBRACKETS);
8✔
2751
                                }
2752
                        }
2753
/*
2754
                        Disable the 'warming up' with smaller buckets.
2755

2756
                        numpasses = 0;
2757
                        thrbufsiz = thrbufsiz0;
2758
*/
2759
                        AN0.lastinindex = -1;
6✔
2760
                }
2761
                MasterWaitAll();
44✔
2762
        }
2763
#endif
2764
/*
2765
          #] Whole brackets : 
2766

2767
        Now the loop to start a bucket
2768
*/
2769
        for(;;) {
15,052✔
2770
                if ( fromspectator ) {
15,052✔
2771
                        ter = GetFromSpectator(thr->threadbuffer,fromspectator-1);
12✔
2772
                        if ( ter == 0 ) fromspectator = 0;
12✔
2773
                }
2774
                else {
2775
                        ter = GetTermP(B0,thr->threadbuffer);
15,040✔
2776
/*
2777
                        At this point we could check whether the input term is
2778
                        just an expression that resides in a scratch file.
2779
                        If this is the case we should store the current input info
2780
                        (file and buffer content) and redirect the input.
2781
                        At the end we can go back to where we were.
2782
                        There are two possibilities: we are in the same scratchfile
2783
                        as the main input and the other expression is still in the
2784
                        input buffer, or we have to do some reading. The reading is
2785
                        of course done in GetTerm.
2786

2787
                        How to set this up can also be studied in TestSub (in file proces.c)
2788
                        where it checks for EXPRESSION.
2789
*/
2790
                }
2791
                if ( ter < 0 ) break;
15,044✔
2792
                if ( ter == 0 ) { endofinput = 1; goto Finalize; }
15,052✔
2793
                dd = AN0.deferskipped;
11,300✔
2794
                if ( AR0.DeferFlag ) {
11,300✔
2795
                        defcount = 0;
114✔
2796
                        thr->deferbuffer[defcount++] = AR0.DefPosition;
114✔
2797
                        ttco = thr->compressbuffer; t1 = AR0.CompressBuffer; j = *t1;
114✔
2798
                        NCOPY(ttco,t1,j);
3,698✔
2799
                }
2800
                else if ( first && ( AC.CollectFun == 0 ) ) { /* Brackets ? */
11,186✔
2801
                        first = 0;
3,808✔
2802
                        t1 = tstop = thr->threadbuffer;
3,808✔
2803
                        tstop += *tstop; tstop -= ABS(tstop[-1]);
3,808✔
2804
                        t1++;
3,808✔
2805
                        while ( t1 < tstop ) {
8,744✔
2806
                                if ( t1[0] == HAAKJE ) { bra = 1; break; }
4,992✔
2807
                                t1 += t1[1];
4,936✔
2808
                        }
2809
                        t1 = thr->threadbuffer;
2810
                }
2811
/*
2812
                Check whether we have a collect,function going. If so execute it.
2813
*/
2814
                if ( AC.CollectFun && *(thr->threadbuffer) < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
11,300✔
2815
                        if ( ( dd = GetMoreTerms(thr->threadbuffer) ) < 0 ) {
20✔
2816
                                LowerSortLevel(); goto ProcErr;
×
2817
                        }
2818
                }
2819
/*
2820
                Check whether we have a priority task:
2821
*/
2822
                if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
11,300✔
2823
/*
2824
                Now put more terms in the bucket. Position tt after the first term
2825
*/
2826
                tt = thr->threadbuffer; tt += *tt;
11,300✔
2827
                thr->totnum = 1;
11,300✔
2828
                thr->usenum = 0;
11,300✔
2829
/*
2830
                Next we worry about the 'slow startup' in which we make the initial
2831
                buckets smaller, so that we get all threads busy as soon as possible.
2832
*/
2833
                if ( numpasses > 0 ) {
11,300✔
2834
                        numbucket++;
7,984✔
2835
                        if ( numbucket >= numberofworkers ) {
7,984✔
2836
                                numbucket = 0;
1,538✔
2837
                                numpasses--;
1,538✔
2838
                                if ( numpasses == 0 ) thrbufsiz = thrbufsiz0;
1,538✔
2839
                                else                  thrbufsiz = thrbufsiz0 / (2 << numpasses);
1,324✔
2840
                        }
2841
                        thrbufsiz2 = thrbufsiz + thrbufsiz/5; /* for completing brackets */
7,984✔
2842
                }
2843
/*
2844
                we have already 1+dd terms
2845
*/
2846
                while ( ( dd < thrbufsiz ) &&
695,454✔
2847
                        ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer/((LONG)sizeof(WORD)) - 2 ) ) {
684,286✔
2848
/*
2849
                        First check:
2850
*/
2851
                        if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
684,286✔
2852
/*
2853
                        There is room in the bucket. Fill yet another term.
2854
*/
2855
                        if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
684,286✔
2856
                        dd++;
684,154✔
2857
                        thr->totnum++;
684,154✔
2858
                        dd += AN0.deferskipped;
684,154✔
2859
                        if ( AR0.DeferFlag ) {
684,154✔
2860
                                thr->deferbuffer[defcount++] = AR0.DefPosition;
298✔
2861
                                t1 = AR0.CompressBuffer; j = *t1;
298✔
2862
                                NCOPY(ttco,t1,j);
9,742✔
2863
                        }
2864
                        if ( AC.CollectFun && *tt < (AM.MaxTer/((LONG)sizeof(WORD))-10) ) {
684,154✔
2865
                                if ( ( ddd = GetMoreTerms(tt) ) < 0 ) {
×
2866
                                        LowerSortLevel(); goto ProcErr;
×
2867
                                }
2868
                                dd += ddd;
×
2869
                        }
2870
                        t1 = tt;
684,154✔
2871
                        tt += *tt;
684,154✔
2872
                }
2873
/*
2874
                Check whether there are regular brackets and if we have no DeferFlag
2875
                and no collect, we try to add more terms till we finish the current
2876
                bracket. We should however not overdo it. Let us say: up to 20%
2877
                more terms are allowed.
2878
*/
2879
                if ( bra ) {
11,300✔
2880
                        tstop = t1 + *t1; tstop -= ABS(tstop[-1]);
400✔
2881
                        t2 = t1+1;
400✔
2882
                        while ( t2 < tstop ) {
784✔
2883
                                if ( t2[0] == HAAKJE ) { break; }
784✔
2884
                                t2 += t2[1];
384✔
2885
                        }
2886
                        if ( t2[0] == HAAKJE ) {
400✔
2887
                          t2 += t2[1]; num = t2 - t1;
400✔
2888
                          while ( ( dd < thrbufsiz2 ) &&
894✔
2889
                                ( tt - thr->threadbuffer ) < ( thr->threadbuffersize - AM.MaxTer - 2 ) ) {
504✔
2890
/*
2891
                                First check:
2892
*/
2893
                                if ( topofavailables > 0 && numberoffullbuckets > 0 ) SendOneBucket(LOWESTLEVELGENERATION);
504✔
2894
/*
2895
                                There is room in the bucket. Fill yet another term.
2896
*/
2897
                                if ( GetTermP(B0,tt) == 0 ) { endofinput = 1; break; }
504✔
2898
/*
2899
                                Same bracket?
2900
*/
2901
                                tstop = tt + *tt; tstop -= ABS(tstop[-1]);
500✔
2902
                                if ( tstop-tt < num ) { /* Different: abort */
500✔
2903
                                        AR0.KeptInHold = 1;
×
2904
                                        break;
×
2905
                                }
2906
                                for ( i = 1; i < num; i++ ) {
4,476✔
2907
                                        if ( t1[i] != tt[i] ) break;
3,982✔
2908
                                }
2909
                                if ( i < num ) { /* Different: abort */
500✔
2910
                                        AR0.KeptInHold = 1;
6✔
2911
                                        break;
6✔
2912
                                }
2913
/*
2914
                                Same bracket. We need this term.
2915
*/
2916
                                dd++;
494✔
2917
                                thr->totnum++;
494✔
2918
                                tt += *tt;
494✔
2919
                          }
2920
                        }
2921
                }
2922
                thr->ddterms = dd; /* total number of terms including keep brackets */
11,300✔
2923
                thr->firstterm = AN0.ninterms;
11,300✔
2924
                AN0.ninterms += dd;
11,300✔
2925
                *tt = 0;           /* mark end of bucket */
11,300✔
2926
                thr->free = BUCKETFILLED;
11,300✔
2927
                thr->type = BUCKETDOINGTERMS;
11,300✔
2928
                numberoffullbuckets++;
11,300✔
2929
                if ( topofavailables <= 0 && endofinput == 0 ) {
11,300✔
2930
/*
2931
                        Problem: topofavailables may already be > 0, but the
2932
                        thread has not yet gone into waiting. Can the signal get lost?
2933
                        How can we tell that a thread is waiting for a signal?
2934

2935
                        All threads are busy. Try to load up another bucket.
2936
                        In the future we could be more sophisticated.
2937
                        At the moment we load a complete bucket which could be
2938
                        1000 terms or even more.
2939
                        In principle it is better to keep a full bucket ready
2940
                        and check after each term we put in the next bucket. That
2941
                        way we don't waste time of the workers.
2942
*/
2943
                        for ( j = 0; j < numthreadbuckets; j++ ) {
35,576✔
2944
                                switch ( threadbuckets[j]->free ) {
32,335✔
2945
                                        case BUCKETFREE:
2946
                                                thr = threadbuckets[j];
2,624✔
2947
                                                if ( !endofinput ) goto NextBucket;
2,624✔
2948
/*
2949
                                                If we are at the end of the input we mark
2950
                                                the free buckets in a special way. That way
2951
                                                we don't keep running into them.
2952
*/
2953
                                                thr->free = BUCKETATEND;
2954
                                                break;
2955
                                        case BUCKETCOMINGFREE:
295✔
2956
                                                thr = threadbuckets[j];
295✔
2957
                                                thr->free = BUCKETFREE;
295✔
2958
/*
2959
                                                Bucket has just been finished.
2960
                                                Put at the end of the list. We don't want
2961
                                                an early bucket to wait to be treated last.
2962
*/
2963
                                                for ( k = j+1; k < numthreadbuckets; k++ )
1,836✔
2964
                                                        threadbuckets[k-1] = threadbuckets[k];
1,541✔
2965
                                                threadbuckets[numthreadbuckets-1] = thr;
295✔
2966
                                                j--;   /* we have to redo the same number j. */
295✔
2967
                                                break;
295✔
2968
                                        default:
2969
                                                break;
2970
                                }
2971
                        }
2972
/*
2973
                        We have no free bucket or we are at the end.
2974
                        The only thing we can do now is wait for a worker to come free,
2975
                        provided there are still buckets to send.
2976
*/
2977
                }
2978
/*
2979
                Look for the next bucket to send. There is at least one full bucket!
2980
*/
2981
                for ( j = 0; j < numthreadbuckets; j++ ) {
13,332✔
2982
                        if ( threadbuckets[j]->free == BUCKETFILLED ) {
13,332✔
2983
                                thr = threadbuckets[j];
8,676✔
2984
                                for ( k = j+1; k < numthreadbuckets; k++ )
48,116✔
2985
                                        threadbuckets[k-1] = threadbuckets[k];
39,440✔
2986
                                threadbuckets[numthreadbuckets-1] = thr;
8,676✔
2987
                                break;
8,676✔
2988
                        }
2989
                }
2990
/*
2991
                Wait for a thread to become available
2992
                The bucket we are going to use is in thr.
2993
*/
2994
DoBucket:;
9,523✔
2995
                AN0.ninterms++;
11,733✔
2996
                while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
16,712✔
2997
/*
2998
                Prepare the thread. Give it the term and variables.
2999
*/
3000
                LoadOneThread(0,id,thr,0);
11,733✔
3001
                LOCK(thr->lock);
11,733✔
3002
                thr->busy = BUCKETASSIGNED;
11,733✔
3003
                UNLOCK(thr->lock);
11,733✔
3004
                thr->free = BUCKETINUSE;
11,733✔
3005
                numberoffullbuckets--;
11,733✔
3006
/*
3007
                And signal the thread to run.
3008
                Form now on we may only interfere with this bucket
3009
                1: after it has been marked BUCKETCOMINGFREE
3010
                2: when thr->busy == BUCKETDOINGTERM and then only when protected by
3011
                   thr->lock. This would be for load balancing.
3012
*/
3013
                WakeupThread(id,LOWESTLEVELGENERATION);
11,733✔
3014
/*                AN0.ninterms += thr->ddterms; */
3015
/*
3016
                Now look whether there is another bucket filled and a worker available
3017
*/
3018
                if ( topofavailables > 0 ) {  /* there is a worker */
11,733✔
3019
                        for ( j = 0; j < numthreadbuckets; j++ ) {
44,199✔
3020
                                if ( threadbuckets[j]->free == BUCKETFILLED ) {
39,157✔
3021
                                        thr = threadbuckets[j];
2,210✔
3022
                                        for ( k = j+1; k < numthreadbuckets; k++ )
9,881✔
3023
                                                threadbuckets[k-1] = threadbuckets[k];
7,671✔
3024
                                        threadbuckets[numthreadbuckets-1] = thr;
2,210✔
3025
                                        goto DoBucket; /* and we found a bucket */
2,210✔
3026
                                }
3027
                        }
3028
/*
3029
                        no bucket is loaded but there is a thread available
3030
                        find a bucket to load. If there is none (all are USED or ATEND)
3031
                        we jump out of the loop.
3032
*/
3033
                        for ( j = 0; j < numthreadbuckets; j++ ) {
7,451✔
3034
                                switch ( threadbuckets[j]->free ) {
7,233✔
3035
                                        case BUCKETFREE:
4,869✔
3036
                                                thr = threadbuckets[j];
4,869✔
3037
                                                if ( !endofinput ) goto NextBucket;
4,869✔
3038
                                                thr->free = BUCKETATEND;
45✔
3039
                                                break;
45✔
3040
                                        case BUCKETCOMINGFREE:
1,257✔
3041
                                                thr = threadbuckets[j];
1,257✔
3042
                                                if ( endofinput ) {
1,257✔
3043
                                                        thr->free = BUCKETATEND;
531✔
3044
                                                }
3045
                                                else {
3046
                                                        thr->free = BUCKETFREE;
726✔
3047
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
5,353✔
3048
                                                                threadbuckets[k-1] = threadbuckets[k];
4,627✔
3049
                                                        threadbuckets[numthreadbuckets-1] = thr;
726✔
3050
                                                        j--;
726✔
3051
                                                }
3052
                                                break;
3053
                                        default:
3054
                                                break;
3055
                                }
3056
                        }
3057
                        if ( j >= numthreadbuckets ) break;
218✔
3058
                }
3059
                else {
3060
/*
3061
                        No worker available.
3062
                        Look for a bucket to load.
3063
                        Its number will be in "still"
3064
*/
3065
Finalize:;
4,481✔
3066
                        still = -1;
8,487✔
3067
                        for ( j = 0; j < numthreadbuckets; j++ ) {
55,811✔
3068
                                switch ( threadbuckets[j]->free ) {
51,044✔
3069
                                        case BUCKETFREE:
21,673✔
3070
                                                thr = threadbuckets[j];
21,673✔
3071
                                                if ( !endofinput ) goto NextBucket;
21,673✔
3072
                                                thr->free = BUCKETATEND;
17,953✔
3073
                                                break;
17,953✔
3074
                                        case BUCKETCOMINGFREE:
5,775✔
3075
                                                thr = threadbuckets[j];
5,775✔
3076
                                                if ( endofinput ) thr->free = BUCKETATEND;
5,775✔
3077
                                                else {
3078
                                                        thr->free = BUCKETFREE;
4,997✔
3079
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
28,595✔
3080
                                                                threadbuckets[k-1] = threadbuckets[k];
23,598✔
3081
                                                        threadbuckets[numthreadbuckets-1] = thr;
4,997✔
3082
                                                        j--;
4,997✔
3083
                                                }
3084
                                                break;
3085
                                        case BUCKETFILLED:
6,067✔
3086
                                                if ( still < 0 ) still = j;
6,067✔
3087
                                                break;
3088
                                        default:
3089
                                                break;
3090
                                }
3091
                        }
3092
                        if ( still < 0 ) {
4,767✔
3093
/*
3094
                                No buckets to be executed and no buckets FREE.
3095
                                We must be at the end. Break out of the loop.
3096
*/
3097
                                break;
3098
                        }
3099
                        thr = threadbuckets[still];
847✔
3100
                        for ( k = still+1; k < numthreadbuckets; k++ )
4,747✔
3101
                                threadbuckets[k-1] = threadbuckets[k];
3,900✔
3102
                        threadbuckets[numthreadbuckets-1] = thr;
847✔
3103
                        goto DoBucket;
847✔
3104
                }
3105
NextBucket:;
3,884✔
3106
        }
3107
/*
3108
        Now the stage one load balancing.
3109
        If the load has been readjusted we have again filled buckets.
3110
        In that case we jump back in the loop.
3111

3112
        Tricky point: when do the workers see the new value of AT.LoadBalancing?
3113
        It should activate the locks on thr->busy
3114
*/
3115
        if ( AC.ThreadBalancing ) {
4,138✔
3116
                for ( id = 1; id <= numberofworkers; id++ ) {
16,564✔
3117
                        AB[id]->T.LoadBalancing = 1;
12,426✔
3118
                }
3119
                if ( LoadReadjusted() ) goto Finalize;
4,138✔
3120
                for ( id = 1; id <= numberofworkers; id++ ) {
15,536✔
3121
                        AB[id]->T.LoadBalancing = 0;
11,652✔
3122
                }
3123
        }
3124
        if ( AC.ThreadBalancing ) {
3,884✔
3125
/*
3126
                The AS.Balancing flag should have Generator look for
3127
                free workers and apply the "buro" method.
3128

3129
                There is still a serious problem.
3130
                When for instance a sum_, there may be space created in a local
3131
                compiler buffer for a wildcard substitution or whatever.
3132
                Compiler buffer execution scribble space.....
3133
                This isn't copied along?
3134
                Look up ebufnum. There are 12 places with AddRHS!
3135
                Problem: one process allocates in ebuf. Then term is given to
3136
                other process. It would like to use from this ebuf, but the sender
3137
                finishes first and removes the ebuf (and/or overwrites it).
3138

3139
                Other problem: local $ variables aren't copied along.
3140
*/
3141
                AS.Balancing = 0;
3,884✔
3142
        }
3143
        MasterWaitAll();
3,884✔
3144
        AS.Balancing = 0;
3,808✔
3145
/*
3146
        When we deal with the last expression we can now remove the input
3147
        scratch file. This saves potentially much disk space (up to 1/3)
3148
*/
3149
        if ( LastExpression ) {
3,808✔
3150
                UpdateMaxSize();
1,836✔
3151
                if ( AR0.infile->handle >= 0 ) {
1,836✔
3152
                        CloseFile(AR0.infile->handle);
12✔
3153
                        AR0.infile->handle = -1;
12✔
3154
                        remove(AR0.infile->name);
12✔
3155
                        PUTZERO(AR0.infile->POposition);
12✔
3156
                        AR0.infile->POfill = AR0.infile->POfull = AR0.infile->PObuffer;
12✔
3157
                }
3158
        }
3159
/*
3160
        We order the threads to finish in the MasterMerge routine
3161
        It will start with waiting for all threads to finish.
3162
        One could make an administration in which threads that have
3163
        finished can start already with the final sort but
3164
        1: The load balancing should not make this super urgent
3165
        2: It would definitely not be very compatible with the second
3166
           stage load balancing.
3167
*/
3168
        oldgzipCompress = AR0.gzipCompress;
3,808✔
3169
        AR0.gzipCompress = 0;
3,808✔
3170
        if ( AR0.outtohide ) AR0.outfile = AR0.hidefile;
3,808✔
3171
        if ( MasterMerge() < 0 ) {
3,808✔
3172
                if ( AR0.outtohide ) AR0.outfile = oldoutfile;
×
3173
                AR0.gzipCompress = oldgzipCompress;
×
3174
                goto ProcErr;
×
3175
        }
3176
        if ( AR0.outtohide ) AR0.outfile = oldoutfile;
3,804✔
3177
        AR0.gzipCompress = oldgzipCompress;
3,804✔
3178
/*
3179
        Now wait for all threads to be ready to give them the cleaning up signal.
3180
        With the new MasterMerge routine we can do the cleanup already automatically
3181
        avoiding having to send these signals.
3182
*/
3183
        MasterWaitAll();
3,804✔
3184
        AR0.sLevel--;
3,804✔
3185
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
15,216✔
3186
                if ( GetThread(id) > 0 ) WakeupThread(id,CLEANUPEXPRESSION);
11,412✔
3187
        }
3188
        e->numdummies = 0;
3,804✔
3189
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
15,216✔
3190
                if ( AB[id]->R.MaxDum - AM.IndDum > e->numdummies )
11,412✔
3191
                        e->numdummies = AB[id]->R.MaxDum - AM.IndDum;
92✔
3192
                AR0.expchanged |= AB[id]->R.expchanged;
11,412✔
3193
        }
3194
/*
3195
        And wait for all to be clean.
3196
*/
3197
        MasterWaitAll();
3,804✔
3198
        AT0.WorkPointer = oldworkpointer;
3,804✔
3199
        return(0);
3,804✔
3200
ProcErr:;
3201
        return(-1);
3202
}
3203

3204
/*
3205
          #] ThreadsProcessor : 
3206
          #[ LoadReadjusted :
3207
*/
3208
/**
3209
 *        This routine does the load readjustment at the end of a module.
3210
 *        It may be that there are still some threads that have a bucket full of
3211
 *        difficult terms. In that case we steal the bucket from such a thread
3212
 *        and redistribute the terms over the available buckets to be sent to
3213
 *        the free threads. As we steal all remaining terms from the bucket
3214
 *        it can happen that eventually the same worker gets some of the terms
3215
 *        back at a later stage.
3216
 *
3217
 *        The only tricky point is the stealing process. We have to do this
3218
 *        without having to send signals or testing locks for each term processed.
3219
 *        The lock is set around thr->busy when AT.LoadBalancing == 1 but
3220
 *        when does the worker see this? (caching?)
3221
 *
3222
 *        Remark: the thr->busy == BUCKETASSIGNED flag is to prevent stealing
3223
 *        from a thread that has not done anything yet.
3224
 */
3225

3226
int LoadReadjusted(void)
4,138✔
3227
{
3228
        ALLPRIVATES *B0 = AB[0];
4,138✔
3229
        THREADBUCKET *thr = 0, *thrtogo = 0;
4,138✔
3230
        int numtogo, numfree, numbusy, n, nperbucket, extra, i, j, u, bus;
4,138✔
3231
        LONG numinput;
4,138✔
3232
        WORD *t1, *c1, *t2, *c2, *t3;
4,138✔
3233
/*
3234
        Start with waiting for at least one free processor.
3235
        We don't want the master competing for time when all are busy.
3236
*/
3237
        while ( topofavailables <= 0 ) MasterWait();
4,609✔
3238
/*
3239
        Now look for the fullest bucket and make a list of free buckets
3240
        The bad part is that most numbers can change at any moment.
3241
*/
3242
restart:;
4,142✔
3243
        numtogo = 0;
4,142✔
3244
        numfree = 0;
4,142✔
3245
        numbusy = 0;
4,142✔
3246
        for ( j = 0; j < numthreadbuckets; j++ ) {
29,026✔
3247
                thr = threadbuckets[j];
24,884✔
3248
                if ( thr->free == BUCKETFREE || thr->free == BUCKETATEND
24,884✔
3249
                || thr->free == BUCKETCOMINGFREE ) {
5,167✔
3250
                        freebuckets[numfree++] = thr;
20,291✔
3251
                }
3252
                else if ( thr->type != BUCKETDOINGTERMS ) {}
4,593✔
3253
                else if ( thr->totnum > 1 ) { /* never steal from a bucket with one term */
4,593✔
3254
                        LOCK(thr->lock);
656✔
3255
                        bus = thr->busy;
656✔
3256
                        UNLOCK(thr->lock);
656✔
3257
                        if ( thr->free == BUCKETINUSE ) {
656✔
3258
                                n = thr->totnum-thr->usenum;
465✔
3259
                                if ( bus == BUCKETASSIGNED ) numbusy++;
465✔
3260
                                else if ( ( bus != BUCKETASSIGNED )
350✔
3261
                                           && ( n > numtogo ) ) {
3262
                                        numtogo = n;
242✔
3263
                                        thrtogo = thr;
242✔
3264
                                }
3265
                        }
3266
                        else if ( bus == BUCKETTOBERELEASED
191✔
3267
                         && thr->free == BUCKETRELEASED ) {
182✔
3268
                                freebuckets[numfree++] = thr;
182✔
3269
                                thr->free = BUCKETATEND;
182✔
3270
                                LOCK(thr->lock);
182✔
3271
                                thr->busy = BUCKETPREPARINGTERM;
182✔
3272
                                UNLOCK(thr->lock);
182✔
3273
                        }
3274
                }
3275
        }
3276
        if ( numfree == 0 ) return(0); /* serious problem */
4,142✔
3277
        if ( numtogo > 0 ) {   /* provisionally there is something to be stolen */
4,142✔
3278
                thr = thrtogo;
193✔
3279
/*
3280
                If the number has changed there is good progress.
3281
                Maybe there is another thread that needs assistance.
3282
                We start all over.
3283
*/
3284
                if ( thr->totnum-thr->usenum < numtogo ) goto restart;
193✔
3285
/*
3286
                If the thread is in the term loading phase
3287
                (thr->busy == BUCKETPREPARINGTERM) we better stay away from it.
3288
                We wait now for the thread to be busy, and don't allow it
3289
                now to drop out of this state till we are done here.
3290
                This all depends on whether AT.LoadBalancing == 1 is seen by
3291
                the thread.
3292
*/
3293
                LOCK(thr->lock);
191✔
3294
                if ( thr->busy != BUCKETDOINGTERM ) {
191✔
3295
                        UNLOCK(thr->lock);
2✔
3296
                        goto restart;
2✔
3297
                }
3298
                if ( thr->totnum-thr->usenum < numtogo ) {
189✔
UNCOV
3299
                        UNLOCK(thr->lock);
×
UNCOV
3300
                        goto restart;
×
3301
                }
3302
                thr->free = BUCKETTERMINATED;
189✔
3303
/*
3304
                The above will signal the thread we want to terminate.
3305
                Next all effort goes into making sure the landing is soft.
3306
                Unfortunately we don't want to wait for a signal, because the thread
3307
                may be working for a long time on a single term.
3308
*/
3309
                if ( thr->usenum == thr->totnum ) {
189✔
3310
/*
3311
                        Terminated in the mean time or by now working on the
3312
                        last term. Try again.
3313
*/
3314
                        thr->free = BUCKETATEND;
×
3315
                        UNLOCK(thr->lock);
×
3316
                        goto restart;
×
3317
                }
3318
                goto intercepted;
189✔
3319
        }
3320
/* This has always been commented. Indeed no lock is held here. */
3321
/*        UNLOCK(thr->lock); */
3322
        if ( numbusy > 0 ) {
3,949✔
3323
                /* JD: this avoids large runtimes for tform tests under valgrind.
3324
                   What seems to happen is we return from here, goto Finalize, and
3325
                   end up in LoadReadjusted again without the threads having a
3326
                   chance to update their busy status. Then we end up here again.
3327
                   Sleep the thread for, say, 1us to allow threads to aquire the lock. */
3328
                struct timespec sleeptime;
65✔
3329
                sleeptime.tv_sec = 0;
65✔
3330
                sleeptime.tv_nsec = 1000L;
65✔
3331
                nanosleep(&sleeptime, NULL);
65✔
3332
                return(1); /* Wait a bit.... */
65✔
3333
        }
3334
        return(0);
3335
intercepted:;
189✔
3336
/*
3337
        We intercepted one successfully. Now it becomes interesting. Action:
3338
        1: determine how many terms per free bucket.
3339
        2: find the first untreated term.
3340
        3: put the terms in the free buckets.
3341

3342
        Remember: we still have the lock to avoid interference from the thread
3343
        that is being robbed. We were holding it and then jumped here with
3344
        goto intercepted.
3345
*/
3346
        numinput = thr->firstterm + thr->usenum;
189✔
3347
        nperbucket = numtogo / numfree;
189✔
3348
        extra = numtogo - nperbucket*numfree;
189✔
3349
        if ( AR0.DeferFlag ) {
189✔
3350
                t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
5✔
3351
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
14✔
3352
                t3 = t1;
5✔
3353
                if ( extra > 0 ) {
5✔
3354
                  for ( i = 0; i < extra; i++ ) {
15✔
3355
                        thrtogo = freebuckets[i];
10✔
3356
                        t2 = thrtogo->threadbuffer;
10✔
3357
                        c2 = thrtogo->compressbuffer;
10✔
3358
                        thrtogo->free = BUCKETFILLED;
10✔
3359
                        thrtogo->type = BUCKETDOINGTERMS;
10✔
3360
                        thrtogo->totnum = nperbucket+1;
10✔
3361
                        thrtogo->ddterms = 0;
10✔
3362
                        thrtogo->usenum = 0;
10✔
3363
                        thrtogo->busy = BUCKETASSIGNED;
10✔
3364
                        thrtogo->firstterm = numinput;
10✔
3365
                        numinput += nperbucket+1;
10✔
3366
                        for ( n = 0; n <= nperbucket; n++ ) {
21✔
3367
                                j = *t1; NCOPY(t2,t1,j);
244✔
3368
                                j = *c1; NCOPY(c2,c1,j);
317✔
3369
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
11✔
3370
                        }
3371
                        *t2 = *c2 = 0;
10✔
3372
                  }
3373
                }
3374
                if ( nperbucket > 0 ) {
5✔
3375
                  for ( i = extra; i < numfree; i++ ) {
3✔
3376
                        thrtogo = freebuckets[i];
2✔
3377
                        t2 = thrtogo->threadbuffer;
2✔
3378
                        c2 = thrtogo->compressbuffer;
2✔
3379
                        thrtogo->free = BUCKETFILLED;
2✔
3380
                        thrtogo->type = BUCKETDOINGTERMS;
2✔
3381
                        thrtogo->totnum = nperbucket;
2✔
3382
                        thrtogo->ddterms = 0;
2✔
3383
                        thrtogo->usenum = 0;
2✔
3384
                        thrtogo->busy = BUCKETASSIGNED;
2✔
3385
                        thrtogo->firstterm = numinput;
2✔
3386
                        numinput += nperbucket;
2✔
3387
                        for ( n = 0; n < nperbucket; n++ ) {
4✔
3388
                                j = *t1; NCOPY(t2,t1,j);
31✔
3389
                                j = *c1; NCOPY(c2,c1,j);
43✔
3390
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
2✔
3391
                        }
3392
                        *t2 = *c2 = 0;
2✔
3393
                  }
3394
                }
3395
        }
3396
        else {
3397
                t1 = thr->threadbuffer;
184✔
3398
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
7,013✔
3399
                t3 = t1;
184✔
3400
                if ( extra > 0 ) {
184✔
3401
                  for ( i = 0; i < extra; i++ ) {
431✔
3402
                        thrtogo = freebuckets[i];
287✔
3403
                        t2 = thrtogo->threadbuffer;
287✔
3404
                        thrtogo->free = BUCKETFILLED;
287✔
3405
                        thrtogo->type = BUCKETDOINGTERMS;
287✔
3406
                        thrtogo->totnum = nperbucket+1;
287✔
3407
                        thrtogo->ddterms = 0;
287✔
3408
                        thrtogo->usenum = 0;
287✔
3409
                        thrtogo->busy = BUCKETASSIGNED;
287✔
3410
                        thrtogo->firstterm = numinput;
287✔
3411
                        numinput += nperbucket+1;
287✔
3412
                        for ( n = 0; n <= nperbucket; n++ ) {
3,445✔
3413
                                j = *t1; NCOPY(t2,t1,j);
591,868✔
3414
                        }
3415
                        *t2 = 0;
287✔
3416
                  }
3417
                }
3418
                if ( nperbucket > 0 ) {
184✔
3419
                  for ( i = extra; i < numfree; i++ ) {
494✔
3420
                        thrtogo = freebuckets[i];
359✔
3421
                        t2 = thrtogo->threadbuffer;
359✔
3422
                        thrtogo->free = BUCKETFILLED;
359✔
3423
                        thrtogo->type = BUCKETDOINGTERMS;
359✔
3424
                        thrtogo->totnum = nperbucket;
359✔
3425
                        thrtogo->ddterms = 0;
359✔
3426
                        thrtogo->usenum = 0;
359✔
3427
                        thrtogo->busy = BUCKETASSIGNED;
359✔
3428
                        thrtogo->firstterm = numinput;
359✔
3429
                        numinput += nperbucket;
359✔
3430
                        for ( n = 0; n < nperbucket; n++ ) {
8,332✔
3431
                                j = *t1; NCOPY(t2,t1,j);
1,426,925✔
3432
                        }
3433
                        *t2 = 0;
359✔
3434
                  }
3435
                }
3436
        }
3437
        *t3 = 0;   /* This is some form of extra insurance */
189✔
3438
        if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
189✔
3439
                thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
×
3440
        }
3441
        UNLOCK(thr->lock);
189✔
3442
        return(1);
189✔
3443
}
3444

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

3507
int PutToMaster(PHEAD WORD *term)
14,016,281✔
3508
{
3509
        int i,j,nexti,ret = 0;
14,016,281✔
3510
        WORD *t, *fill, *top, zero = 0;
14,016,281✔
3511
        if ( term == 0 ) { /* Mark the end of the expression */
14,016,281✔
3512
                t = &zero; j = 1;
3513
        }
3514
        else {
3515
                t = term; ret = j = *term;
14,001,065✔
3516
                if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
14,001,065✔
3517
        }
3518
        i = AT.SB.FillBlock;          /* The block we are working at */
14,016,281✔
3519
        fill = AT.SB.MasterFill[i];     /* Where we are filling */
14,016,281✔
3520
        top = AT.SB.MasterStop[i];      /* End of the block */
14,016,281✔
3521
        while ( j > 0 ) {
28,032,572✔
3522
                while ( j > 0 && fill < top ) {
374,066,021✔
3523
                        *fill++ = *t++; j--;
360,049,730✔
3524
                }
3525
                if ( j > 0 ) {
14,016,291✔
3526
/*
3527
                        We reached the end of the block.
3528
                        Get the next block and release this block.
3529
                        The order is important. This is why there should be at least
3530
                        4 blocks or deadlocks can occur.
3531
*/
3532
                        nexti = i+1;
10✔
3533
                        if ( nexti > AT.SB.MasterNumBlocks ) {
10✔
3534
                                nexti = 1;
×
3535
                        }
3536
                        LOCK(AT.SB.MasterBlockLock[nexti]);
10✔
3537
                        UNLOCK(AT.SB.MasterBlockLock[i]);
10✔
3538
                        AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
10✔
3539
                        AT.SB.FillBlock = i = nexti;
10✔
3540
                        fill = AT.SB.MasterStart[i];
10✔
3541
                        top = AT.SB.MasterStop[i];
10✔
3542
                }
3543
        }
3544
        AT.SB.MasterFill[i] = fill;
14,016,281✔
3545
        return(ret);
14,016,281✔
3546
}
3547

3548
/*
3549
          #] PutToMaster : 
3550
          #[ SortBotOut :
3551
*/
3552
 
3553
#ifdef WITHSORTBOTS
3554

3555
/**
3556
 *                This is the output routine of the SortBots.
3557
 *                It can run PutToMaster, except for the final merge.
3558
 *                In that case we need to do special things like calling PutOut.
3559
 *                Hence the first thing we have to do is to figure out where our
3560
 *                output should be going.
3561
 */
3562

3563
int
3564
SortBotOut(PHEAD WORD *term)
9,228,104✔
3565
{
3566
        WORD im;
9,228,104✔
3567

3568
        if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
9,228,104✔
3569

3570
        if ( term == 0 ) {
4,571,572✔
3571
                if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
1,902✔
3572
                ADDPOS(AT.SS->SizeInFile[0],1);
1,902✔
3573
                return(0);
1,902✔
3574
        }
3575
        else {
3576
                numberofterms++;
4,569,670✔
3577
                if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
4,569,670✔
3578
                        MLOCK(ErrorMessageLock);
×
3579
                        MesPrint("Called from MasterMerge/SortBotOut");
×
3580
                        MUNLOCK(ErrorMessageLock);
×
3581
                        return(-1);
×
3582
                }
3583
                ADDPOS(AT.SS->SizeInFile[0],im);
4,569,670✔
3584
                return(im);
4,569,670✔
3585
        }
3586
}
3587

3588
#endif
3589

3590
/*
3591
          #] SortBotOut : 
3592
          #[ MasterMerge :
3593
*/
3594
/**
3595
 *        This is the routine in which the master merges the sorted output that
3596
 *        comes from the workers. It is similar to MergePatches in sort.c from which
3597
 *        it takes much code.
3598
 *        The important concept here is that we want the master to be working as
3599
 *        little as possible because it constitutes the bottleneck.
3600
 *        The workers fill the buffers of the master. These buffers are divided
3601
 *        into parts for each worker as is done with the file patches in MergePatches
3602
 *        but now also each worker part is divided into blocks. This allows the
3603
 *        worker to fill blocks while the master is already working on blocks that
3604
 *        were filled before. The blocks are arranged in a circular fashion.
3605
 *        The whole is controlled by locks which seems faster than setting it up
3606
 *        with signals.
3607
 *
3608
 *        This routine is run by the master when we don't use the sortbots.
3609
 */
3610

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

3700
        Now construct the tree:
3701
*/
3702
        lpat = 1;
3703
        do { lpat <<= 1; } while ( lpat < S->lPatch );
1,902✔
3704
        mpat = ( lpat >> 1 ) - 1;
1,902✔
3705
        k = lpat - S->lPatch;
1,902✔
3706
/*
3707
        k is the number of empty places in the tree. they will
3708
        be at the even positions from 2 to 2*k
3709
*/
3710
        for ( i = 1; i < lpat; i++ ) { S->tree[i] = -1; }
3,804✔
3711
        for ( i = 1; i <= k; i++ ) {
1,902✔
3712
                im = ( i * 2 ) - 1;
×
3713
                poin[im] = AB[i]->T.SB.MasterStart[AB[i]->T.SB.MasterBlock];
×
3714
                poin2[im] = poin[im] + *(poin[im]);
×
3715
                S->used[i] = im;
×
3716
                S->ktoi[im] = i-1;
×
3717
                S->tree[mpat+i] = 0;
×
3718
                poin[im-1] = poin2[im-1] = 0;
×
3719
        }
3720
        for ( i = (k*2)+1; i <= lpat; i++ ) {
5,706✔
3721
                S->used[i-k] = i;
3,804✔
3722
                S->ktoi[i] = i-k-1;
3,804✔
3723
                poin[i] = AB[i-k]->T.SB.MasterStart[AB[i-k]->T.SB.MasterBlock];
3,804✔
3724
                poin2[i] = poin[i] + *(poin[i]);
3,804✔
3725
        }
3726
/*
3727
        the array poin tells the position of the i-th element of the S->tree
3728
        'S->used' is a stack with the S->tree elements that need to be entered
3729
        into the S->tree. at the beginning this is S->lPatch. during the
3730
        sort there will be only very few elements.
3731
        poin2 is the next value of poin. it has to be determined
3732
        before the comparisons as the position or the size of the
3733
        term indicated by poin may change.
3734
        S->ktoi translates a S->tree element back to its stream number.
3735

3736
        start the sort
3737
*/
3738
        level = S->lPatch;
1,902✔
3739
/*
3740
        introduce one term
3741
*/
3742
OneTerm:
4,642,205✔
3743
        k = S->used[level];
4,644,107✔
3744
        i = k + lpat - 1;
4,644,107✔
3745
        if ( !*(poin[k]) ) {
4,644,107✔
3746
                do { if ( !( i >>= 1 ) ) goto EndOfMerge; } while ( !S->tree[i] );
5,706✔
3747
                if ( S->tree[i] == -1 ) {
1,902✔
3748
                        S->tree[i] = 0;
1,548✔
3749
                        level--;
1,548✔
3750
                        goto OneTerm;
1,548✔
3751
                }
3752
                k = S->tree[i];
354✔
3753
                S->used[level] = k;
354✔
3754
                S->tree[i] = 0;
354✔
3755
        }
3756
/*
3757
        move terms down the tree
3758
*/
3759
        while ( i >>= 1 ) {
9,209,973✔
3760
                if ( S->tree[i] > 0 ) {
4,640,303✔
3761
                        if ( ( c = CompareTerms(B0, poin[S->tree[i]],poin[k],(WORD)0) ) > 0 ) {
76,914✔
3762
/*
3763
                                S->tree[i] is the smaller. Exchange and go on.
3764
*/
3765
                                S->used[level] = S->tree[i];
4,209✔
3766
                                S->tree[i] = k;
4,209✔
3767
                                k = S->used[level];
4,209✔
3768
                        }
3769
                        else if ( !c ) {        /* Terms are equal */
72,705✔
3770
/*
3771
                                S->TermsLeft--;
3772
                                        Here the terms are equal and their coefficients
3773
                                        have to be added.
3774
*/
3775
                                l1 = *( m1 = poin[S->tree[i]] );
36,327✔
3776
                                l2 = *( m2 = poin[k] );
36,327✔
3777
                                if ( S->PolyWise ) {  /* Here we work with PolyFun */
36,327✔
3778
                                        WORD *tt1, *w;
1,696✔
3779
                                        tt1 = m1;
1,696✔
3780
                                        m1 += S->PolyWise;
1,696✔
3781
                                        m2 += S->PolyWise;
1,696✔
3782
                                        if ( S->PolyFlag == 2 ) {
1,696✔
3783
                                                w = poly_ratfun_add(B0,m1,m2);
1,694✔
3784
                                                if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
1,694✔
3785
                                                        MLOCK(ErrorMessageLock);
×
3786
                                                        MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
3787
                                                        MUNLOCK(ErrorMessageLock);
×
3788
                                                        Terminate(-1);
×
3789
                                                }
3790
                                                AT0.WorkPointer = w;
1,694✔
3791
                                                if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
1,694✔
3792
                                                        goto cancelled;
1,443✔
3793
                                                }
3794
                                        }
3795
                                        else {
3796
                                                w = AT0.WorkPointer;
2✔
3797
                                                if ( w + m1[1] + m2[1] > AT0.WorkTop ) {
2✔
3798
                                                        MLOCK(ErrorMessageLock);
×
3799
                                                        MesPrint("MasterMerge: A WorkSpace of %10l is too small",AM.WorkSize);
×
3800
                                                        MUNLOCK(ErrorMessageLock);
×
3801
                                                        Terminate(-1);
×
3802
                                                }
3803
                                                AddArgs(B0,m1,m2,w);
2✔
3804
                                        }
3805
                                        r1 = w[1];
253✔
3806
                                        if ( r1 <= FUNHEAD
253✔
3807
                                                || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
253✔
3808
                                                         { goto cancelled; }
×
3809
                                        if ( r1 == m1[1] ) {
253✔
3810
                                                NCOPY(m1,w,r1);
692✔
3811
                                        }
3812
                                        else if ( r1 < m1[1] ) {
248✔
3813
                                                r2 = m1[1] - r1;
15✔
3814
                                                m2 = w + r1;
15✔
3815
                                                m1 += m1[1];
15✔
3816
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
167,584✔
3817
                                                m2 = m1 - r2;
15✔
3818
                                                r1 = S->PolyWise;
15✔
3819
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
194✔
3820
                                                *m1 -= r2;
15✔
3821
                                                poin[S->tree[i]] = m1;
15✔
3822
                                        }
3823
                                        else {
3824
                                                r2 = r1 - m1[1];
233✔
3825
                                                m2 = tt1 - r2;
233✔
3826
                                                r1 = S->PolyWise;
233✔
3827
                                                m1 = tt1;
233✔
3828
                                                *m1 += r2;
233✔
3829
                                                poin[S->tree[i]] = m2;
233✔
3830
                                                NCOPY(m2,m1,r1);
1,750✔
3831
                                                r1 = w[1];
233✔
3832
                                                NCOPY(m2,w,r1);
2,690,806✔
3833
                                        }
3834
                                }
3835
#ifdef WITHFLOAT
3836
                                else if ( AT.SortFloatMode ) {
34,631✔
3837
                                        WORD *term1, *term2;
×
3838
                                        term1 = poin[S->tree[i]];
×
3839
                                        term2 = poin[k];
×
3840
                                        if ( MergeWithFloat(B0, &term1,&term2) == 0 )
×
3841
                                                goto cancelled;
×
3842
                                        poin[S->tree[i]] = term1;
×
3843
                                }
3844
#endif
3845
                                else {
3846
                                        r1 = *( m1 += l1 - 1 );
34,631✔
3847
                                        m1 -= ABS(r1) - 1;
34,631✔
3848
                                        r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
34,631✔
3849
                                        r2 = *( m2 += l2 - 1 );
34,631✔
3850
                                        m2 -= ABS(r2) - 1;
34,631✔
3851
                                        r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
34,631✔
3852

3853
                                        if ( AddRat(B0,(UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
34,631✔
3854
                                                MLOCK(ErrorMessageLock);
×
3855
                                                MesCall("MasterMerge");
×
3856
                                                MUNLOCK(ErrorMessageLock);
×
3857
                                                SETERROR(-1)
×
3858
                                        }
3859

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

4070
/*
4071
          #] MasterMerge : 
4072
          #[ SortBotMasterMerge :
4073
*/
4074
 
4075
#ifdef WITHSORTBOTS
4076

4077
/**
4078
 *        This is the master routine for the final stage in a sortbot merge.
4079
 *        A sortbot merge is a merge in which the output of two workers is
4080
 *        merged into a single output which then can be given as one of two
4081
 *        streams to another sortbot. The idea is that each sortbot is responsible
4082
 *        for one one compare per term. In the end the master does the last
4083
 *        merge of only two streams and writes the result to the output.
4084
 *        There doesn't seem to be an advantage to splitting this last task.
4085
 *
4086
 *        The use of the sortbots gives a measurable improvement but it isn't
4087
 *        optimal yet.
4088
 *
4089
 *        This routine is run as master. Hence B = B0. Etc.
4090
 */
4091

4092
int SortBotMasterMerge(void)
1,904✔
4093
{
4094
        FILEHANDLE *fin, *fout;
1,904✔
4095
        ALLPRIVATES *B = AB[0], *BB;
1,904✔
4096
        POSITION position;
1,904✔
4097
        SORTING *S = AT.SS;
1,904✔
4098
        int i, j;
1,904✔
4099
/*
4100
        Get the sortbots get to claim their writing blocks.
4101
        We have to wait till all have been claimed because they also have to
4102
        claim the last writing blocks of the workers to prevent the head of
4103
        the circular buffer to overrun the tail.
4104

4105
        Before waiting we can do some needed initializations.
4106
        Also the master has to claim the last writing blocks of its input.
4107
*/
4108
        topsortbotavailables = 0;
1,904✔
4109
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
5,712✔
4110
                WakeupThread(i,INISORTBOT);
3,808✔
4111
        }
4112

4113
        AS.MasterSort = 1;
1,904✔
4114
        fout = AR.outfile;
1,904✔
4115
        numberofterms = 0;
1,904✔
4116
        AR.CompressPointer[0] = 0;
1,904✔
4117
        numberclaimed = 0;
1,904✔
4118
        BB = AB[AT.SortBotIn1];
1,904✔
4119
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
1,904✔
4120
        BB = AB[AT.SortBotIn2];
1,904✔
4121
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
1,904✔
4122

4123
        MasterWaitAllSortBots();
1,904✔
4124
/*
4125
        Now we can start up the workers. They will claim their writing blocks.
4126
        Here the master will wait till all writing blocks have been claimed.
4127
*/
4128
        for ( i = 1; i <= numberofworkers; i++ ) {
11,424✔
4129
                j = GetThread(i);
7,616✔
4130
                WakeupThread(i,FINISHEXPRESSION);
7,616✔
4131
        }
4132
/*
4133
        Prepare the output file in the mean time.
4134
*/
4135
        if ( fout->handle >= 0 ) {
1,904✔
4136
                PUTZERO(SortBotPosition);
×
4137
                SeekFile(fout->handle,&SortBotPosition,SEEK_END);
×
4138
                ADDPOS(SortBotPosition,((fout->POfill-fout->PObuffer)*sizeof(WORD)));
×
4139
        }
4140
        else {
4141
                SETBASEPOSITION(SortBotPosition,(fout->POfill-fout->PObuffer)*sizeof(WORD));
1,904✔
4142
        }
4143
        MasterWaitAllBlocks();
1,904✔
4144
/*
4145
        Now we can start the sortbots after which the master goes in
4146
        sortbot mode to do its part of the job (the very final merge and
4147
        the writing to output file).
4148
*/
4149
        topsortbotavailables = 0;
1,904✔
4150
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
5,712✔
4151
                WakeupThread(i,RUNSORTBOT);
3,808✔
4152
        }
4153
        if ( SortBotMerge(BHEAD0) ) {
1,904✔
4154
                MLOCK(ErrorMessageLock);
×
4155
                MesPrint("Called from SortBotMasterMerge");
×
4156
                MUNLOCK(ErrorMessageLock);
×
4157
                AS.MasterSort = 0;
×
4158
                return(-1);
×
4159
        }
4160
/*
4161
        And next the cleanup
4162
*/
4163
        if ( S->file.handle >= 0 )
1,902✔
4164
        {
4165
                fin = &S->file;
×
4166
                CloseFile(fin->handle);
×
4167
                remove(fin->name);
×
4168
                fin->handle = -1;
×
4169
        }
4170
        position = S->SizeInFile[0];
1,902✔
4171
        MULPOS(position,sizeof(WORD));
1,902✔
4172
        S->GenTerms = 0;
1,902✔
4173
        for ( j = 1; j <= numberofworkers; j++ ) {
9,510✔
4174
                S->GenTerms += AB[j]->T.SS->GenTerms;
7,608✔
4175
        }
4176
        S->TermsLeft = numberofterms;
1,902✔
4177
        WriteStats(&position,STATSPOSTSORT,NOCHECKLOGTYPE);
1,902✔
4178
        Expressions[AR.CurExpr].counter = S->TermsLeft;
1,902✔
4179
        Expressions[AR.CurExpr].size = position;
1,902✔
4180
        AS.MasterSort = 0;
1,902✔
4181
/*
4182
        The next statement is to prevent one of the sortbots not having
4183
        completely cleaned up before the next module starts.
4184
        If this statement is omitted every once in a while one of the sortbots
4185
        is still running when the next expression starts and misses its
4186
        initialization. The result is usually disastrous.
4187
*/
4188
        MasterWaitAllSortBots();
1,902✔
4189

4190
        return(0);
1,902✔
4191
}
4192

4193
#endif
4194

4195
/*
4196
          #] SortBotMasterMerge : 
4197
          #[ SortBotMerge :
4198
*/
4199
 
4200
#ifdef WITHSORTBOTS
4201

4202
/**
4203
 *        This routine is run by a sortbot and merges two sorted output streams into
4204
 *        a single sorted stream.
4205
 */
4206

4207
int SortBotMerge(PHEAD0)
5,712✔
4208
{
4209
        GETBIDENTITY
4210
        ALLPRIVATES *Bin1 = AB[AT.SortBotIn1],*Bin2 = AB[AT.SortBotIn2];
5,712✔
4211
        WORD *term1, *term2, *next, *wp;
5,712✔
4212
        int blin1, blin2;        /* Current block numbers */
5,712✔
4213
        int error = 0;
5,712✔
4214
        WORD l1, l2, *m1, *m2, *w, r1, r2, r3, r33, r31, *tt1, ii;
5,712✔
4215
        WORD *to, *from, im, c;
5,712✔
4216
        UWORD *coef;
5,712✔
4217
        SORTING *S = AT.SS;
5,712✔
4218
#ifdef WITHFLOAT
4219
        WORD *fun1, *fun2, *fun3, *tstop1, *tstop2, size1, size2, size3, l3, jj, *m3;
5,712✔
4220
#endif
4221
/*
4222
        Set the pointers to the input terms and the output space
4223
*/
4224
        coef = AN.SoScratC;
5,712✔
4225
        blin1 = 1;
5,712✔
4226
        blin2 = 1;
5,712✔
4227
        if ( AT.identity == 0 ) {
5,712✔
4228
                wp = AT.WorkPointer;
1,904✔
4229
        }
4230
        else {
4231
                wp = AT.WorkPointer = AT.WorkSpace;
3,808✔
4232
        }
4233
/*
4234
        Get the locks for reading the input
4235
        This means that we can start once these locks have been cleared
4236
        which means that there will be input.
4237
*/
4238
        LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
5,712✔
4239
        LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
5,706✔
4240

4241
        term1 = Bin1->T.SB.MasterStart[blin1];
5,706✔
4242
        term2 = Bin2->T.SB.MasterStart[blin2];
5,706✔
4243
        AT.SB.FillBlock = 1;
5,706✔
4244
/*
4245
        Now the main loop. Keep going until one of the two hits the end.
4246
*/
4247
        while ( *term1 && *term2 ) {
233,525✔
4248
                if ( ( c = CompareTerms(BHEAD term1,term2,(WORD)0) ) > 0 ) {
227,819✔
4249
/*
4250
                        #[ One is smallest :
4251
*/
4252
                        if ( SortBotOut(BHEAD term1) < 0 ) {
75,014✔
4253
                                MLOCK(ErrorMessageLock);
×
4254
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4255
                                MUNLOCK(ErrorMessageLock);
×
4256
                                error = -1;
×
4257
                                goto ReturnError;
×
4258
                        }
4259
                        im = *term1;
75,014✔
4260
                        next = term1 + im;
75,014✔
4261
                        if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
75,014✔
4262
                        next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
74,750✔
4263
                                if ( blin1 == 1 ) {
×
4264
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
×
4265
                                }
4266
                                else {
4267
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
×
4268
                                }
4269
                                if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
×
4270
/*
4271
                                        Move the remainder down into block 0
4272
*/
4273
                                        to = Bin1->T.SB.MasterStart[1];
×
4274
                                        from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
×
4275
                                        while ( from > next ) *--to = *--from;
×
4276
                                        next = to;
4277
                                        blin1 = 1;
4278
                                }
4279
                                else {
4280
                                        blin1++;
×
4281
                                }
4282
                                LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
×
4283
                                Bin1->T.SB.MasterBlock = blin1;
×
4284
                        }
4285
                        term1 = next;
4286
/*
4287
                        #] One is smallest : 
4288
*/
4289
                }
4290
                else if ( c < 0 ) {
152,805✔
4291
/*
4292
                        #[ Two is smallest :
4293
*/
4294
                        if ( SortBotOut(BHEAD term2) < 0 ) {
80,916✔
4295
                                MLOCK(ErrorMessageLock);
×
4296
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4297
                                MUNLOCK(ErrorMessageLock);
×
4298
                                error = -1;
×
4299
                                goto ReturnError;
×
4300
                        }
4301
next2:                im = *term2;
80,916✔
4302
                        next = term2 + im;
152,805✔
4303
                        if ( next >= Bin2->T.SB.MasterStop[blin2] || ( *next
152,805✔
4304
                        && next+*next+COMPINC > Bin2->T.SB.MasterStop[blin2] ) ) {
152,424✔
4305
                                if ( blin2 == 1 ) {
×
4306
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
×
4307
                                }
4308
                                else {
4309
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
×
4310
                                }
4311
                                if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
×
4312
/*
4313
                                        Move the remainder down into block 0
4314
*/
4315
                                        to = Bin2->T.SB.MasterStart[1];
×
4316
                                        from = Bin2->T.SB.MasterStop[Bin2->T.SB.MasterNumBlocks];
×
4317
                                        while ( from > next ) *--to = *--from;
×
4318
                                        next = to;
4319
                                        blin2 = 1;
4320
                                }
4321
                                else {
4322
                                        blin2++;
×
4323
                                }
4324
                                LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
×
4325
                                Bin2->T.SB.MasterBlock = blin2;
×
4326
                        }
4327
                        term2 = next;
4328
/*
4329
                        #] Two is smallest : 
4330
*/
4331
                }
4332
                else {
4333
/*
4334
                        #[ Equal :
4335
*/
4336
                        l1 = *( m1 = term1 );
71,889✔
4337
                        l2 = *( m2 = term2 );
71,889✔
4338
                        if ( S->PolyWise ) {  /* Here we work with PolyFun */
71,889✔
4339
                                tt1 = m1;
2,140✔
4340
                                m1 += S->PolyWise;
2,140✔
4341
                                m2 += S->PolyWise;
2,140✔
4342
                                if ( S->PolyFlag == 2 ) {
2,140✔
4343
                                        AT.WorkPointer = wp;
2,136✔
4344
                                        w = poly_ratfun_add(BHEAD m1,m2);
2,136✔
4345
                                        if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
2,136✔
4346
                                                MLOCK(ErrorMessageLock);
×
4347
                                                MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
4348
                                                MUNLOCK(ErrorMessageLock);
×
4349
                                                Terminate(-1);
×
4350
                                        }
4351
                                        AT.WorkPointer = wp;
2,136✔
4352
                                        if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
2,136✔
4353
                                                goto cancelled;
1,825✔
4354
                                        }
4355
                                }
4356
                                else {
4357
                                        w = wp;
4✔
4358
                                        if ( w + m1[1] + m2[1] > AT.WorkTop ) {
4✔
4359
                                                MLOCK(ErrorMessageLock);
×
4360
                                                MesPrint("SortBotMerge(%d): A Maxtermsize of %10l is too small",
×
4361
                                                                AT.identity,AM.MaxTer/sizeof(WORD));
×
4362
                                                MesPrint("m1[1] = %d, m2[1] = %d, Space = %l",m1[1],m2[1],(LONG)(AT.WorkTop-wp));
×
4363
                                                PrintTerm(term1,"term1");
×
4364
                                                PrintTerm(term2,"term2");
×
4365
                                                MesPrint("PolyWise = %d",S->PolyWise);
×
4366
                                                MUNLOCK(ErrorMessageLock);
×
4367
                                                Terminate(-1);
×
4368
                                        }
4369
                                        AddArgs(BHEAD m1,m2,w);
4✔
4370
                                }
4371
                                r1 = w[1];
315✔
4372
                                if ( r1 <= FUNHEAD
315✔
4373
                                        || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
315✔
4374
                                                 { goto cancelled; }
×
4375
                                if ( r1 == m1[1] ) {
315✔
4376
                                        NCOPY(m1,w,r1);
54✔
4377
                                }
4378
                                else if ( r1 < m1[1] ) {
313✔
4379
                                        r2 = m1[1] - r1;
26✔
4380
                                        m2 = w + r1;
26✔
4381
                                        m1 += m1[1];
26✔
4382
                                        while ( --r1 >= 0 ) *--m1 = *--m2;
170,740✔
4383
                                        m2 = m1 - r2;
26✔
4384
                                        r1 = S->PolyWise;
26✔
4385
                                        while ( --r1 >= 0 ) *--m1 = *--m2;
329✔
4386
                                        *m1 -= r2;
26✔
4387
                                        term1 = m1;
26✔
4388
                                }
4389
                                else {
4390
                                        r2 = r1 - m1[1];
287✔
4391
                                        m2 = tt1 - r2;
287✔
4392
                                        r1 = S->PolyWise;
287✔
4393
                                        m1 = tt1;
287✔
4394
                                        *m1 += r2;
287✔
4395
                                        term1 = m2;
287✔
4396
                                        NCOPY(m2,m1,r1);
2,274✔
4397
                                        r1 = w[1];
287✔
4398
                                        NCOPY(m2,w,r1);
2,931,894✔
4399
                                }
4400
                        }
4401
#ifdef WITHFLOAT
4402
                        else if ( AT.SortFloatMode ) {
69,749✔
4403
/*
4404
                                The terms are in m1/term1 and m2/term2 and their length in l1 and l2.
4405
                                We have to locate the floats which have already been
4406
                                verified in the compare routine. Once we have the new
4407
                                term we can jump to the code that writes away the
4408
                                result after adding the rationals.
4409
*/
4410
                                tstop1 = m1+l1; size1 = tstop1[-1]; tstop1 -= ABS(size1);
×
4411
                                tstop2 = m2+l2; size2 = tstop2[-1]; tstop2 -= ABS(size2);
×
4412
                                if ( AT.SortFloatMode == 3 ) {
×
4413
                                        fun1 = m1+1;
×
4414
                                        while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
×
4415
                                                fun1 += fun1[1];
4416
                                        }
4417
                                        if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
×
4418
                                        UnpackFloat(aux1,fun1);
×
4419
                                        fun2 = m2+1;
×
4420
                                        while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
×
4421
                                                fun2 += fun2[1];
4422
                                        }
4423
                                        if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
×
4424
                                        UnpackFloat(aux2,fun2);
×
4425
                                }
4426
                                else if ( AT.SortFloatMode == 1 ) {
×
4427
                                        fun1 = m1+1;
×
4428
                                        while ( fun1[0] != FLOATFUN && fun1+fun1[1] < tstop1 ) {
×
4429
                                                fun1 += fun1[1];
4430
                                        }
4431
                                        if ( size1 < 0 ) fun1[FUNHEAD+3] = -fun1[FUNHEAD+3];
×
4432
                                        UnpackFloat(aux1,fun1);
×
4433
                                        fun2 = tstop2;
×
4434
                                        RatToFloat(aux2,(UWORD *)fun2,size2);
×
4435
                                }
4436
                                else if ( AT.SortFloatMode == 2 ) {
×
4437
                                        fun1 = tstop1;
×
4438
                                        RatToFloat(aux1,(UWORD *)fun1,size1);
×
4439
                                        fun2 = m2+1;
×
4440
                                        while ( fun2[0] != FLOATFUN && fun2+fun2[1] < tstop2 ) {
×
4441
                                                fun2 += fun2[1];
4442
                                        }
4443
                                        if ( size2 < 0 ) fun2[FUNHEAD+3] = -fun2[FUNHEAD+3];
×
4444
                                        UnpackFloat(aux2,fun2);
×
4445
                                }
4446
                                else {
4447
                                        MLOCK(ErrorMessageLock);
×
4448
                                        MesPrint("Illegal value %d for AT.SortFloatMode in SortBotMerge.",AT.SortFloatMode);
×
4449
                                        MUNLOCK(ErrorMessageLock);
×
4450
                                        Terminate(-1);
×
4451
                                        return(0);
×
4452
                                }
4453
                                mpf_add(aux3,aux1,aux2);
×
4454
                                size3 = mpf_sgn(aux3);
×
4455
                                if ( size3 == 0 ) { /* Cancelling! Rare! */
×
4456
                                        goto cancelled;
×
4457
                                }
4458
                                else if ( size3 < 0 ) mpf_neg(aux3,aux3);
×
4459
                                fun3 = TermMalloc("MasterMerge");
×
4460
                                PackFloat(fun3,aux3);
×
4461
                                l3 = fun3[1]+(fun1-m1)+3; /* new size */
×
4462

4463
                                if ( l3 != l1 ) {
×
4464
/*
4465
                                        Copy it all to wp
4466
*/
4467
                                        if ( (l3)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
×
4468
                                                MLOCK(ErrorMessageLock);
×
4469
                                                MesPrint("MasterMerge: Coefficient overflow during sort");
×
4470
                                                MUNLOCK(ErrorMessageLock);
×
4471
                                                goto ReturnError;
×
4472
                                        }
4473
                    m3 = wp; m2 = term1;
4474
                                        while ( m2 < fun1 ) *m3++ = *m2++;
×
4475
                                        for ( jj = 0; jj < fun3[1]; jj++ ) *m3++ = fun3[jj];
×
4476
                                        *m3++ = 1; *m3++ = 1;
×
4477
                                        *m3++ = size3 < 0 ? -3: 3;
×
4478
                                        *wp = m3-wp;
×
4479
                                        TermFree(fun3,"MasterMerge");
×
4480
                                        goto PutOutwp;
×
4481
                                }
4482
                                for ( jj = 0; jj < fun3[1]; jj++ ) fun1[jj] = fun3[jj];
×
4483
                                fun1 += fun3[1];
×
4484
                                *fun1++ = 1; *fun1++ = 1;
×
4485
                                *fun1++ = size3 < 0 ? -3: 3;
×
4486
                                *term1 = fun1-term1;
×
4487
                                TermFree(fun3,"MasterMerge");
×
4488
                        }
4489
#endif
4490
                        else {
4491
                                r1 = *( m1 += l1 - 1 );
69,749✔
4492
                                m1 -= ABS(r1) - 1;
69,749✔
4493
                                r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
69,749✔
4494
                                r2 = *( m2 += l2 - 1 );
69,749✔
4495
                                m2 -= ABS(r2) - 1;
69,749✔
4496
                                r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
69,749✔
4497

4498
                                if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
69,749✔
4499
                                        MLOCK(ErrorMessageLock);
×
4500
                                        MesCall("SortBotMerge");
×
4501
                                        MUNLOCK(ErrorMessageLock);
×
4502
                                        SETERROR(-1)
×
4503
                                }
4504

4505
                                if ( AN.ncmod != 0 ) {
69,749✔
4506
                                        if ( ( AC.modmode & POSNEG ) != 0 ) {
×
4507
                                                NormalModulus(coef,&r3);
×
4508
                                        }
4509
                                        else if ( BigLong(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod)) >= 0 ) {
×
4510
                                                SubPLon(coef,r3,(UWORD *)AC.cmod,ABS(AN.ncmod),coef,&r3);
×
4511
                                                coef[r3] = 1;
×
4512
                                                for ( ii = 1; ii < r3; ii++ ) coef[r3+ii] = 0;
×
4513
                                        }
4514
                                }
4515
                                if ( !r3 ) { goto cancelled; }
69,749✔
4516
                                r3 *= 2;
5,099✔
4517
                                r33 = ( r3 > 0 ) ? ( r3 + 1 ) : ( r3 - 1 );
5,099✔
4518
                                if ( r3 < 0 ) r3 = -r3;
5,099✔
4519
                                if ( r1 < 0 ) r1 = -r1;
5,099✔
4520
                                r1 *= 2;
5,099✔
4521
                                r31 = r3 - r1;
5,099✔
4522
                                if ( !r31 ) {                /* copy coef into term1 */
5,099✔
4523
                                        m2 = (WORD *)coef; im = r3;
4524
                                        NCOPY(m1,m2,im);
15,364✔
4525
                                        *m1 = r33;
5,098✔
4526
                                }
4527
                                else {
4528
                                        to = wp; from = term1;
4529
                                        while ( from < m1 ) *to++ = *from++;
2✔
4530
                                        from = (WORD *)coef; im = r3;
1✔
4531
                                        NCOPY(to,from,im);
9✔
4532
                                        *to++ = r33;
1✔
4533
                                        wp[0] = to - wp;
1✔
4534
PutOutwp:
1✔
4535
                                        if ( SortBotOut(BHEAD wp) < 0 ) {
1✔
4536
                                                MLOCK(ErrorMessageLock);
×
4537
                                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4538
                                                MUNLOCK(ErrorMessageLock);
×
4539
                                                error = -1;
×
4540
                                                goto ReturnError;
×
4541
                                        }
4542
                                        goto cancelled;
1✔
4543
                                }
4544
                        }
4545
                        if ( SortBotOut(BHEAD term1) < 0 ) {
5,413✔
4546
                                MLOCK(ErrorMessageLock);
×
4547
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4548
                                MUNLOCK(ErrorMessageLock);
×
4549
                                error = -1;
×
4550
                                goto ReturnError;
×
4551
                        }
4552
cancelled:;                /* Now we need two new terms */
5,413✔
4553
                        im = *term1;
71,889✔
4554
                        next = term1 + im;
71,889✔
4555
                        if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
71,889✔
4556
                        next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
71,771✔
4557
                                if ( blin1 == 1 ) {
×
4558
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
×
4559
                                }
4560
                                else {
4561
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
×
4562
                                }
4563
                                if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
×
4564
/*
4565
                                        Move the remainder down into block 0
4566
*/
4567
                                        to = Bin1->T.SB.MasterStart[1];
×
4568
                                        from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
×
4569
                                        while ( from > next ) *--to = *--from;
×
4570
                                        next = to;
4571
                                        blin1 = 1;
4572
                                }
4573
                                else {
4574
                                        blin1++;
×
4575
                                }
4576
                                LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
×
4577
                                Bin1->T.SB.MasterBlock = blin1;
×
4578
                        }
4579
                        term1 = next;
71,889✔
4580
                        goto next2;
71,889✔
4581
/*
4582
                        #] Equal : 
4583
*/
4584
                }
4585
        }
4586
/*
4587
        Copy the tail
4588
*/
4589
        if ( *term1 ) {
5,706✔
4590
/*
4591
                        #[ Tail in one :
4592
*/
4593
                while ( *term1 ) {
4,895,617✔
4594
                        if ( SortBotOut(BHEAD term1) < 0 ) {
4,892,939✔
4595
                                MLOCK(ErrorMessageLock);
×
4596
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4597
                                MUNLOCK(ErrorMessageLock);
×
4598
                                error = -1;
×
4599
                                goto ReturnError;
×
4600
                        }
4601
                        im = *term1;
4,892,939✔
4602
                        next = term1 + im;
4,892,939✔
4603
                        if ( next >= Bin1->T.SB.MasterStop[blin1] || ( *next &&
4,892,939✔
4604
                        next+*next+COMPINC > Bin1->T.SB.MasterStop[blin1] ) ) {
4,890,261✔
4605
                                if ( blin1 == 1 ) {
4✔
4606
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
2✔
4607
                                }
4608
                                else {
4609
                                        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
2✔
4610
                                }
4611
                                if ( blin1 == Bin1->T.SB.MasterNumBlocks ) {
4✔
4612
/*
4613
                                        Move the remainder down into block 0
4614
*/
4615
                                        to = Bin1->T.SB.MasterStart[1];
×
4616
                                        from = Bin1->T.SB.MasterStop[Bin1->T.SB.MasterNumBlocks];
×
4617
                                        while ( from > next ) *--to = *--from;
×
4618
                                        next = to;
4619
                                        blin1 = 1;
4620
                                }
4621
                                else {
4622
                                        blin1++;
4✔
4623
                                }
4624
                                LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
4✔
4625
                                Bin1->T.SB.MasterBlock = blin1;
4✔
4626
                        }
4627
                        term1 = next;
4628
                }
4629
/*
4630
                        #] Tail in one : 
4631
*/
4632
        }
4633
        else if ( *term2 ) {
3,028✔
4634
/*
4635
                        #[ Tail in two :
4636
*/
4637
                while ( *term2 ) {
4,169,096✔
4638
                        if ( SortBotOut(BHEAD term2) < 0 ) {
4,168,115✔
4639
                                MLOCK(ErrorMessageLock);
×
4640
                                MesPrint("Called from SortBotMerge with thread = %d",AT.identity);
×
4641
                                MUNLOCK(ErrorMessageLock);
×
4642
                                error = -1;
×
4643
                                goto ReturnError;
×
4644
                        }
4645
                        im = *term2;
4,168,115✔
4646
                        next = term2 + im;
4,168,115✔
4647
                        if ( next >= Bin2->T.SB.MasterStop[blin2] || ( *next
4,168,115✔
4648
                        && next+*next+COMPINC > Bin2->T.SB.MasterStop[blin2] ) ) {
4,167,134✔
4649
                                if ( blin2 == 1 ) {
4✔
4650
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
2✔
4651
                                }
4652
                                else {
4653
                                        UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
2✔
4654
                                }
4655
                                if ( blin2 == Bin2->T.SB.MasterNumBlocks ) {
4✔
4656
/*
4657
                                        Move the remainder down into block 0
4658
*/
4659
                                        to = Bin2->T.SB.MasterStart[1];
×
4660
                                        from = Bin2->T.SB.MasterStop[Bin2->T.SB.MasterNumBlocks];
×
4661
                                        while ( from > next ) *--to = *--from;
×
4662
                                        next = to;
4663
                                        blin2 = 1;
4664
                                }
4665
                                else {
4666
                                        blin2++;
4✔
4667
                                }
4668
                                LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
4✔
4669
                                Bin2->T.SB.MasterBlock = blin2;
4✔
4670
                        }
4671
                        term2 = next;
4672
                }
4673
/*
4674
                        #] Tail in two : 
4675
*/
4676
        }
4677
        SortBotOut(BHEAD 0);
5,706✔
4678
ReturnError:;
5,706✔
4679
/*
4680
        Release all locks
4681
*/
4682
        UNLOCK(Bin1->T.SB.MasterBlockLock[blin1]);
5,706✔
4683
        if ( blin1 > 1 ) {
5,706✔
4684
                UNLOCK(Bin1->T.SB.MasterBlockLock[blin1-1]);
2✔
4685
        }
4686
        else {
4687
                UNLOCK(Bin1->T.SB.MasterBlockLock[Bin1->T.SB.MasterNumBlocks]);
5,704✔
4688
        }
4689
        UNLOCK(Bin2->T.SB.MasterBlockLock[blin2]);
5,706✔
4690
        if ( blin2 > 1 ) {
5,706✔
4691
                UNLOCK(Bin2->T.SB.MasterBlockLock[blin2-1]);
2✔
4692
        }
4693
        else {
4694
                UNLOCK(Bin2->T.SB.MasterBlockLock[Bin2->T.SB.MasterNumBlocks]);
5,704✔
4695
        }
4696
        if ( AT.identity > 0 ) {
5,706✔
4697
                UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
3,804✔
4698
        }
4699
/*
4700
        And that was all folks
4701
*/
4702
        return(error);
4703
}
4704

4705
#endif
4706

4707
/*
4708
          #] SortBotMerge : 
4709
          #[ IniSortBlocks :
4710
*/
4711
 
4712
static int SortBlocksInitialized = 0;
4713

4714
/**
4715
 *        Initializes the blocks in the sort buffers of the master.
4716
 *        These blocks are needed to keep both the workers and the master working
4717
 *        simultaneously. See also the commentary at the routine MasterMerge.
4718
 */
4719

4720
int IniSortBlocks(int numworkers)
1,296✔
4721
{
4722
        ALLPRIVATES *B;
1,296✔
4723
        SORTING *S;
1,296✔
4724
        LONG totalsize, workersize, blocksize, numberofterms;
1,296✔
4725
        int maxter, id, j;
1,296✔
4726
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
1,296✔
4727
        WORD *w;
1,296✔
4728

4729
        if ( SortBlocksInitialized ) return(0);
1,296✔
4730
        SortBlocksInitialized = 1;
1,296✔
4731
        if ( numworkers == 0 ) return(0);
1,296✔
4732

4733
#ifdef WITHSORTBOTS
4734
        if ( numworkers > 2 ) {
1,280✔
4735
                numparts = 2*numworkers - 2;
640✔
4736
                numberofblocks = numberofblocks/2;
640✔
4737
        }
4738
        else {
4739
                numparts = numworkers;
4740
        }
4741
#else
4742
        numparts = numworkers;
4743
#endif
4744
        S = AM.S0;
1,280✔
4745
        totalsize = S->LargeSize + S->SmallEsize;
1,280✔
4746
        workersize = totalsize / numparts;
1,280✔
4747
        maxter = AM.MaxTer/sizeof(WORD);
1,280✔
4748
        blocksize = ( workersize - maxter )/numberofblocks;
1,280✔
4749
        numberofterms = blocksize / maxter;
1,280✔
4750
        if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
1,280✔
4751
/*
4752
                This should have been taken care of in RecalcSetups.
4753
*/
4754
                MesPrint("We have a problem with the size of the blocks in IniSortBlocks");
×
4755
                Terminate(-1);
×
4756
        }
4757
/*
4758
        Layout:  For each worker
4759
                                block 0: size is maxter WORDS
4760
                                numberofblocks blocks of size blocksize WORDS
4761
*/
4762
        w = S->lBuffer;
1,280✔
4763
        if ( w == 0 ) w = S->sBuffer;
1,280✔
4764
        for ( id = 1; id <= numparts; id++ ) {
6,400✔
4765
                B = AB[id];
5,120✔
4766
                AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
10,240✔
4767
                        sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
5,120✔
4768
                AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
5,120✔
4769
                AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
5,120✔
4770
                AT.SB.MasterStop = AT.SB.MasterFill  + (numberofblocks+1);
5,120✔
4771
                AT.SB.MasterNumBlocks = numberofblocks;
5,120✔
4772
                AT.SB.MasterBlock = 0;
5,120✔
4773
                AT.SB.FillBlock = 0;
5,120✔
4774
                AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
5,120✔
4775
                w += maxter;
5,120✔
4776
                AT.SB.MasterStop[0] = w;
5,120✔
4777
                AT.SB.MasterBlockLock[0] = dummylock;
5,120✔
4778
                for ( j = 1; j <= numberofblocks; j++ ) {
37,120✔
4779
                        AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
32,000✔
4780
                        w += blocksize;
32,000✔
4781
                        AT.SB.MasterStop[j] = w;
32,000✔
4782
                        AT.SB.MasterBlockLock[j] = dummylock;
32,000✔
4783
                }
4784
        }
4785
        if ( w > S->sTop2 ) {
1,280✔
4786
                MesPrint("Counting problem in IniSortBlocks");
×
4787
                Terminate(-1);
×
4788
        }
4789
        return(0);
4790
}
4791

4792
/*
4793
          #] IniSortBlocks : 
4794
          #[ UpdateSortBlocks :
4795
*/
4796
 
4797
/**
4798
 *        A version of IniSortBlocks which only updates the pointers in the master's
4799
 *        buffer, to be used after reallocation of that buffer.
4800
 */
4801
int UpdateSortBlocks(int numworkers)
16✔
4802
{
4803
        ALLPRIVATES *B;
16✔
4804
        SORTING *S;
16✔
4805
        LONG totalsize, workersize, blocksize, numberofterms;
16✔
4806
        int maxter, id, j;
16✔
4807
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
16✔
4808
        WORD *w;
16✔
4809

4810
        if ( numworkers == 0 ) return(0);
16✔
4811

4812
#ifdef WITHSORTBOTS
4813
        if ( numworkers > 2 ) {
16✔
4814
                numparts = 2*numworkers - 2;
8✔
4815
                numberofblocks = numberofblocks/2;
8✔
4816
        }
4817
        else {
4818
                numparts = numworkers;
4819
        }
4820
#else
4821
        numparts = numworkers;
4822
#endif
4823
        S = AM.S0;
16✔
4824
        totalsize = S->LargeSize + S->SmallEsize;
16✔
4825
        workersize = totalsize / numparts;
16✔
4826
        maxter = AM.MaxTer/sizeof(WORD);
16✔
4827
        blocksize = ( workersize - maxter )/numberofblocks;
16✔
4828
        numberofterms = blocksize / maxter;
16✔
4829
        if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
16✔
4830
/*
4831
                This should have been taken care of in RecalcSetups.
4832
*/
4833
                MesPrint("We have a problem with the size of the blocks in UpdateSortBlocks");
×
4834
                Terminate(-1);
×
4835
        }
4836
/*
4837
        Layout:  For each worker
4838
                                block 0: size is maxter WORDS
4839
                                numberofblocks blocks of size blocksize WORDS
4840
*/
4841
        w = S->lBuffer;
16✔
4842
        if ( w == 0 ) w = S->sBuffer;
16✔
4843
        for ( id = 1; id <= numparts; id++ ) {
80✔
4844
                B = AB[id];
64✔
4845
                AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
64✔
4846
                w += maxter;
64✔
4847
                AT.SB.MasterStop[0] = w;
64✔
4848
                for ( j = 1; j <= numberofblocks; j++ ) {
464✔
4849
                        AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
400✔
4850
                        w += blocksize;
400✔
4851
                        AT.SB.MasterStop[j] = w;
400✔
4852
                }
4853
        }
4854
        if ( w > S->sTop2 ) {
16✔
4855
                MesPrint("Counting problem in UpdateSortBlocks");
×
4856
                Terminate(-1);
×
4857
        }
4858
        return(0);
4859
}
4860

4861
/*
4862
          #] UpdateSortBlocks : 
4863
          #[ DefineSortBotTree :
4864
*/
4865
 
4866
#ifdef WITHSORTBOTS
4867

4868
/**
4869
 *        To be used in a sortbot merge. It initializes the whole sortbot
4870
 *        system by telling the sortbot which threads provide their input.
4871
 */
4872

4873
void DefineSortBotTree(void)
1,296✔
4874
{
4875
        ALLPRIVATES *B;
1,296✔
4876
        int n, i, from;
1,296✔
4877
        if ( numberofworkers <= 2 ) return;
1,296✔
4878
        n = numberofworkers*2-2;
640✔
4879
        for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
1,920✔
4880
                B = AB[i];
1,280✔
4881
                AT.SortBotIn1 = from++;
1,280✔
4882
                AT.SortBotIn2 = from++;
1,280✔
4883
        }
4884
        B = AB[0];
640✔
4885
        AT.SortBotIn1 = from++;
640✔
4886
        AT.SortBotIn2 = from++;
640✔
4887
}
4888

4889
#endif
4890

4891
/*
4892
          #] DefineSortBotTree : 
4893
          #[ GetTerm2 :
4894

4895
        Routine does a GetTerm but only when a bracket index is involved and
4896
        only from brackets that have been judged not suitable for treatment
4897
        as complete brackets by a single worker. Whether or not a bracket should
4898
        be treated by a single worker is decided by TreatIndexEntry
4899
*/
4900

4901
WORD GetTerm2(PHEAD WORD *term)
3,632✔
4902
{
4903
        WORD *ttco, *tt, retval;
3,632✔
4904
        LONG n,i;
3,632✔
4905
        FILEHANDLE *fi;
3,632✔
4906
        EXPRESSIONS e = AN.expr;
3,632✔
4907
        BRACKETINFO *b  = e->bracketinfo;
3,632✔
4908
        BRACKETINDEX *bi = b->indexbuffer;
3,632✔
4909
        POSITION where, eonfile = AS.OldOnFile[e-Expressions], bstart, bnext;
3,632✔
4910
/*
4911
        1: Get the current position.
4912
*/
4913
        switch ( e->status ) {
3,632✔
4914
                case UNHIDELEXPRESSION:
×
4915
                case UNHIDEGEXPRESSION:
4916
                case DROPHLEXPRESSION:
4917
                case DROPHGEXPRESSION:
4918
                case HIDDENLEXPRESSION:
4919
                case HIDDENGEXPRESSION:
4920
                        fi = AR.hidefile;
×
4921
                        break;
×
4922
                default:
3,632✔
4923
                        fi = AR.infile;
3,632✔
4924
                        break;
3,632✔
4925
        }
4926
        if ( AR.KeptInHold ) {
3,632✔
4927
                retval = GetTerm(BHEAD term);
6✔
4928
                return(retval);
6✔
4929
        }
4930
        SeekScratch(fi,&where);
3,626✔
4931
        if ( AN.lastinindex < 0 ) {
3,626✔
4932
/*
4933
                We have to test whether we have to do the first bracket
4934
*/
4935
                if ( ( n = TreatIndexEntry(BHEAD 0) ) <= 0 ) {
6✔
4936
                        AN.lastinindex = n;
×
4937
                        where = bi[n].start;
×
4938
                        ADD2POS(where,eonfile);
×
4939
                        SetScratch(fi,&where);
×
4940
/*
4941
                        Put the bracket in the Compress buffer.
4942
*/
4943
                        ttco = AR.CompressBuffer;
×
4944
                        tt = b->bracketbuffer + bi[0].bracket;
×
4945
                        i = *tt;
×
4946
                        NCOPY(ttco,tt,i)
×
4947
                        AR.CompressPointer = ttco;
×
4948
                        retval = GetTerm(BHEAD term);
×
4949
                        return(retval);
×
4950
                }
4951
                else AN.lastinindex = n-1;
6✔
4952
        }
4953
/*
4954
        2: Find the corresponding index number
4955
           a: test whether it is in the current bracket
4956
*/
4957
        n = AN.lastinindex;
3,626✔
4958
        bstart = bi[n].start;
3,626✔
4959
        ADD2POS(bstart,eonfile);
3,626✔
4960
        bnext = bi[n].next;
3,626✔
4961
        ADD2POS(bnext,eonfile);
3,626✔
4962
        if ( ISLESSPOS(bstart,where) && ISLESSPOS(where,bnext) ) {
3,626✔
4963
                retval = GetTerm(BHEAD term);
3,572✔
4964
                return(retval);
3,572✔
4965
        }
4966
        for ( n++ ; n < b->indexfill; n++ ) {
154✔
4967
                i = TreatIndexEntry(BHEAD n);
144✔
4968
                if ( i <= 0 ) {
144✔
4969
/*
4970
                        Put the bracket in the Compress buffer.
4971
*/
4972
                        ttco = AR.CompressBuffer;
44✔
4973
                        tt = b->bracketbuffer + bi[n].bracket;
44✔
4974
                        i = *tt;
44✔
4975
                        NCOPY(ttco,tt,i)
564✔
4976
                        AR.CompressPointer = ttco;
44✔
4977
                        AN.lastinindex = n;
44✔
4978
                        where = bi[n].start;
44✔
4979
                        ADD2POS(where,eonfile);
44✔
4980
                        SetScratch(fi,&(where));
44✔
4981
                        retval = GetTerm(BHEAD term);
44✔
4982
                        return(retval);
44✔
4983
                }
4984
                else n += i - 1;
100✔
4985
        }
4986
        return(0);
4987
}
4988

4989
/*
4990
          #] GetTerm2 : 
4991
          #[ TreatIndexEntry :
4992
*/
4993
/**
4994
 *        Routine has to decide whether a bracket has to be sent as a complete
4995
 *        bracket to a worker or whether it has to be treated by the bucket system.
4996
 *        Return value is positive when we should send it as a complete bracket and
4997
 *        0 when it should be done via the buckets.
4998
 *        The positive return value indicates how many brackets should be treated.
4999
 */
5000
 
5001
int TreatIndexEntry(PHEAD LONG n)
408✔
5002
{
5003
        BRACKETINFO *b  = AN.expr->bracketinfo;
408✔
5004
        LONG numbra = b->indexfill - 1, i;
408✔
5005
        LONG totterms;
408✔
5006
        BRACKETINDEX *bi;
408✔
5007
        POSITION pos1, average;
408✔
5008
/*
5009
        1: number of the bracket should be such that there is one bucket
5010
           for each worker remaining.
5011
*/
5012
        if ( ( numbra - n ) <= numberofworkers ) return(0);
408✔
5013
/*
5014
        2: size of the bracket contents should be less than what remains in
5015
           the expression divided by the number of workers.
5016
*/
5017
        bi = b->indexbuffer;
266✔
5018
        DIFPOS(pos1,bi[numbra].next,bi[n].next);  /* Size of what remains */
266✔
5019
        BASEPOSITION(average) = DIVPOS(pos1,(3*numberofworkers));
266✔
5020
        DIFPOS(pos1,bi[n].next,bi[n].start);      /* Size of the current bracket */
266✔
5021
        if ( ISLESSPOS(average,pos1) ) return(0);
266✔
5022
/*
5023
        It passes.
5024
        Now check whether we can do more brackets
5025
*/
5026
        totterms = bi->termsinbracket;
212✔
5027
        if ( totterms > 2*AC.ThreadBucketSize ) return(1);
212✔
5028
        for ( i = 1; i < numbra-n; i++ ) {
720✔
5029
                DIFPOS(pos1,bi[n+i].next,bi[n].start); /* Size of the combined brackets */
720✔
5030
                if ( ISLESSPOS(average,pos1) ) return(i);
720✔
5031
                totterms += bi->termsinbracket;
524✔
5032
                if ( totterms > 2*AC.ThreadBucketSize ) return(i+1);
524✔
5033
        }
5034
/*
5035
        We have a problem at the end of the system. Just do one.
5036
*/
5037
        return(1);
5038
}
5039

5040
/*
5041
          #] TreatIndexEntry : 
5042
          #[ SetHideFiles :
5043
*/
5044

5045
void SetHideFiles(void) {
202,212✔
5046
        int i;
202,212✔
5047
        ALLPRIVATES *B, *B0 = AB[0];
202,212✔
5048
        for ( i = 1; i <= numberofworkers; i++ ) {
808,848✔
5049
                B = AB[i];
606,636✔
5050
                AR.hidefile->handle = AR0.hidefile->handle;
606,636✔
5051
                if ( AR.hidefile->handle < 0 ) {
606,636✔
5052
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
606,636✔
5053
                        AR.hidefile->POstop = AR0.hidefile->POstop;
606,636✔
5054
                        AR.hidefile->POfill = AR0.hidefile->POfill;
606,636✔
5055
                        AR.hidefile->POfull = AR0.hidefile->POfull;
606,636✔
5056
                        AR.hidefile->POsize = AR0.hidefile->POsize;
606,636✔
5057
                        AR.hidefile->POposition = AR0.hidefile->POposition;
606,636✔
5058
                        AR.hidefile->filesize = AR0.hidefile->filesize;
606,636✔
5059
                }
5060
                else {
5061
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
5062
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
5063
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
5064
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
5065
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
5066
                        PUTZERO(AR.hidefile->POposition);
×
5067
                }
5068
        }
5069
}
202,212✔
5070

5071
/*
5072
          #] SetHideFiles : 
5073
          #[ IniFbufs :
5074
*/
5075

5076
void IniFbufs(void)
1,296✔
5077
{
5078
        int i;
1,296✔
5079
        for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
6,432✔
5080
                IniFbuffer(AB[i]->T.fbufnum);
5,136✔
5081
        }
5082
}
1,296✔
5083

5084
/*
5085
          #] IniFbufs : 
5086
          #[ SetMods :
5087
*/
5088

5089
void SetMods(void)
4✔
5090
{
5091
        ALLPRIVATES *B;
4✔
5092
        int i, n, j;
4✔
5093
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
20✔
5094
                B = AB[j];
16✔
5095
                AN.ncmod = AC.ncmod;
16✔
5096
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
16✔
5097
                n = ABS(AN.ncmod);
16✔
5098
                AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
16✔
5099
                for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
32✔
5100
        }
5101
}
4✔
5102

5103
/*
5104
          #] SetMods : 
5105
          #[ UnSetMods :
5106
*/
5107

5108
void UnSetMods(void)
4✔
5109
{
5110
        ALLPRIVATES *B;
4✔
5111
        int j;
4✔
5112
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
20✔
5113
                B = AB[j];
16✔
5114
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
16✔
5115
                AN.cmod = 0;
16✔
5116
        }
5117
}
4✔
5118

5119
/*
5120
          #] UnSetMods : 
5121
          #[ find_Horner_MCTS_expand_tree_threaded :
5122
*/
5123
 
5124
void find_Horner_MCTS_expand_tree_threaded(void) {
111✔
5125
        int id;
111✔
5126
        while (( id = GetAvailableThread() ) < 0)
166✔
5127
                MasterWait();        
55✔
5128
        WakeupThread(id,MCTSEXPANDTREE);
111✔
5129
}
111✔
5130

5131
/*
5132
          #] find_Horner_MCTS_expand_tree_threaded : 
5133
          #[ optimize_expression_given_Horner_threaded :
5134
*/
5135
 
5136
extern void optimize_expression_given_Horner_threaded(void) {
60✔
5137
        int id;
60✔
5138
        while (( id = GetAvailableThread() ) < 0)
60✔
5139
                MasterWait();        
×
5140
        WakeupThread(id,OPTIMIZEEXPRESSION);
60✔
5141
}
60✔
5142

5143
/*
5144
          #] optimize_expression_given_Horner_threaded : 
5145
*/
5146

5147
#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

© 2025 Coveralls, Inc