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

tueda / form / 15241916852

25 May 2025 08:59PM UTC coverage: 47.908% (-2.8%) from 50.743%
15241916852

push

github

tueda
ci: build arm64-windows binaries

39009 of 81425 relevant lines covered (47.91%)

1079780.1 hits per line

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

76.48
/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)
590✔
128
{
129
        pthread_key_create(&identitykey,FinishIdentity);
590✔
130
}
590✔
131

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

140
void FinishIdentity(void *keyp)
2,088✔
141
{
142
        DUMMYUSE(keyp);
2,088✔
143
/*        free(keyp); */
144
}
2,088✔
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)
2,926✔
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);
2,926✔
163
        *identityretval = identityofthreads++;
2,926✔
164
        UNLOCK(numberofthreadslock);
2,926✔
165
        pthread_setspecific(identitykey,(void *)identityretval);
2,926✔
166
        return(*identityretval);
2,926✔
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)
35,578,586✔
185
{
186
        int *identity;
35,578,586✔
187
/*
188
        First a fast exit for when there is at most one thread
189
*/
190
        if ( identityofthreads <= 1 ) return(0);
35,578,586✔
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);
35,577,288✔
200
        return(*identity);
35,577,288✔
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)
590✔
213
{
214
        StartIdentity();
590✔
215
        SetIdentity(&identityretval);
590✔
216
}
590✔
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)
590✔
230
{
231
        AM.handlelock = dummyrwlock;
590✔
232
}
590✔
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)
588✔
256
{
257
        int identity, j, dummy, mul;
588✔
258
        ALLPRIVATES *B;
588✔
259
        pthread_t thethread;
588✔
260
        identity = WhoAmI();
588✔
261

262
#ifdef WITHSORTBOTS
263
        timerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"timerinfo");
588✔
264
        sumtimerinfo = (LONG *)Malloc1(sizeof(LONG)*number*2,"sumtimerinfo");
588✔
265
        for ( j = 0; j < number*2; j++ ) { timerinfo[j] = 0; sumtimerinfo[j] = 0; }
5,268✔
266
        mul = 2;
588✔
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");
588✔
275
        threadpointers = (pthread_t *)Malloc1(sizeof(pthread_t)*number*mul,"threadpointers");
588✔
276
        AB = (ALLPRIVATES **)Malloc1(sizeof(ALLPRIVATES *)*number*mul,"Private structs");
588✔
277

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

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

288
        numberofthreads = number;
588✔
289
        numberofworkers = number - 1;
588✔
290
        threadpointers[identity] = pthread_self();
588✔
291
        topofavailables = 0;
588✔
292
        for ( j = 1; j < number; j++ ) {
2,340✔
293
                if ( pthread_create(&thethread,NULL,RunThread,(void *)(&dummy)) )
1,752✔
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);
588✔
300
        AR.infile = &(AR.Fscr[0]);
588✔
301
        AR.outfile = &(AR.Fscr[1]);
588✔
302
        AR.hidefile = &(AR.Fscr[2]);
588✔
303
        AM.sbuflock = dummylock;
588✔
304
        AS.inputslock = dummylock;
588✔
305
        AS.outputslock = dummylock;
588✔
306
        AS.MaxExprSizeLock = dummylock;
588✔
307
        AP.PreVarLock = dummylock;
588✔
308
        AC.halfmodlock = dummylock;
588✔
309
        MakeThreadBuckets(number,0);
588✔
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();
588✔
316
#ifdef WITHSORTBOTS
317
        if ( numberofworkers > 2 ) {
588✔
318
                numberofsortbots = numberofworkers-2;
292✔
319
                for ( j = numberofworkers+1; j < 2*numberofworkers-1; j++ ) {
876✔
320
                        if ( pthread_create(&thethread,NULL,RunSortBot,(void *)(&dummy)) )
584✔
321
                                goto failure;
×
322
                }
323
        }
324
        else {
325
                numberofsortbots = 0;
296✔
326
        }
327
        MasterWaitAllSortBots();
588✔
328
        DefineSortBotTree();
588✔
329
#endif
330
        IniSortBlocks(number-1);
588✔
331
        AS.MasterSort = 0;
588✔
332
        AM.storefilelock = dummylock;
588✔
333
/*
334
MesPrint("AB = %x %x %x  %d",AB[0],AB[1],AB[2], identityofthreads);
335
*/
336
        return(0);
588✔
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)
2,924✔
380
{
381
        WORD *t, *ScratchBuf;
2,924✔
382
        int i, j, bsize, *bp;
2,924✔
383
        LONG ScratchSize[3], IOsize;
2,924✔
384
        ALLPRIVATES *B;
2,924✔
385
        UBYTE *s;
2,924✔
386

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

397
        bsize = sizeof(ALLPRIVATES);
2,924✔
398
        bsize = (bsize+sizeof(int)-1)/sizeof(int);
2,924✔
399
        B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
2,924✔
400
        for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
17,409,496✔
401

402
        AB[identity] = B;
2,924✔
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);
2,924✔
420

421
#ifdef WITHSORTBOTS
422

423
        if ( identity > numberofworkers ) {
2,924✔
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;
584✔
429
                AT.WorkSpace = (WORD *)Malloc1(length,"WorkSpace");
584✔
430
                AT.WorkTop = AT.WorkSpace + length/sizeof(WORD);
584✔
431
                AT.WorkPointer = AT.WorkSpace;
584✔
432
                AT.identity = identity;
584✔
433
/*
434
                The SB struct gets treated in IniSortBlocks.
435
                The SortBotIn variables will be defined DefineSortBotTree.
436
*/
437
                if ( AN.SoScratC == 0 ) {
584✔
438
                        AN.SoScratC = (UWORD *)Malloc1(2*(AM.MaxTal+2)*sizeof(UWORD),"Scratch in SortBot");
584✔
439
                }
440
                AT.SS = (SORTING *)Malloc1(sizeof(SORTING),"dummy sort buffer");
584✔
441
                AT.SS->PolyFlag = 0;
584✔
442

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

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

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

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

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

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

562
        AN.IndDum = AM.IndDum;
2,340✔
563

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

579
        AR.CompressBuffer = (WORD *)Malloc1((AM.CompressSize+10)*sizeof(WORD),"compresssize");
2,340✔
580
        AR.ComprTop = AR.CompressBuffer + AM.CompressSize;
2,340✔
581
        AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
2,340✔
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");
2,340✔
587
        AT.WorkTop = AT.WorkSpace + AM.WorkSize;
2,340✔
588
        AT.WorkPointer = AT.WorkSpace;
2,340✔
589

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

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

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

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

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

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

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

706
        AT.inprimelist = -1;
2,340✔
707
        AT.sizeprimelist = 0;
2,340✔
708
        AT.primelist = 0;
2,340✔
709
        AT.nfac = AT.nBer = 0;
2,340✔
710
        AT.factorials = 0;
2,340✔
711
        AT.bernoullis = 0;
2,340✔
712
        AR.wranfia = 0;
2,340✔
713
        AR.wranfcall = 0;
2,340✔
714
        AR.wranfnpair1 = NPAIR1;
2,340✔
715
        AR.wranfnpair2 = NPAIR2;
2,340✔
716
        AR.wranfseed = 0;
2,340✔
717
        AN.SplitScratch = 0;
2,340✔
718
        AN.SplitScratchSize = AN.InScratch = 0;
2,340✔
719
        AN.SplitScratch1 = 0;
2,340✔
720
        AN.SplitScratchSize1 = AN.InScratch1 = 0;
2,340✔
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 ) {
2,340✔
726
                AT.S0 = AM.S0;
588✔
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
1,752✔
734
                                                 ,AM.S0->SmallSize*sizeof(WORD)/numberofworkers
1,752✔
735
                                                 ,AM.S0->SmallEsize*sizeof(WORD)/numberofworkers
1,752✔
736
                                                 ,AM.S0->TermsInSmall
737
                                                 ,AM.S0->MaxPatches
738
/*                                                 ,AM.S0->MaxPatches/numberofworkers  */
739
                                                 ,AM.S0->MaxFpatches/numberofworkers
1,752✔
740
                                                 ,AM.S0->file.POsize
1,752✔
741
                                                 ,0);
742
        }
743
        AR.CompressPointer = AR.CompressBuffer;
2,340✔
744
/*
745
        Install the store caches (15-aug-2006 JV)
746
*/
747
        AT.StoreCache = AT.StoreCacheAlloc = 0;
2,340✔
748
        if ( AM.NumStoreCaches > 0 ) {
2,340✔
749
                STORECACHE sa, sb;
2,340✔
750
                LONG size;
2,340✔
751
                size = sizeof(struct StOrEcAcHe)+AM.SizeStoreCache;
2,340✔
752
                size = ((size-1)/sizeof(size_t)+1)*sizeof(size_t);
2,340✔
753
                AT.StoreCacheAlloc = (STORECACHE)Malloc1(size*AM.NumStoreCaches,"StoreCaches");
2,340✔
754
                sa = AT.StoreCache = AT.StoreCacheAlloc;
2,340✔
755
                for ( i = 0; i < AM.NumStoreCaches; i++ ) {
11,700✔
756
                        sb = (STORECACHE)(VOID *)((UBYTE *)sa+size);
9,360✔
757
                        if ( i == AM.NumStoreCaches-1 ) {
9,360✔
758
                                sa->next = 0;
2,340✔
759
                        }
760
                        else {
761
                                sa->next = sb;
7,020✔
762
                        }
763
                        SETBASEPOSITION(sa->position,-1);
9,360✔
764
                        SETBASEPOSITION(sa->toppos,-1);
9,360✔
765
                        sa = sb;
9,360✔
766
                }                
767
        }
768

769
        ReserveTempFiles(2);
2,340✔
770
        return(B);
2,340✔
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)
2,088✔
794
{
795
        timerinfo[identity] = TimeCPU(1);
2,088✔
796
}
2,088✔
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

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)
526✔
833
{
834
        int i;
526✔
835
        for ( i = 1; i <= numberofworkers; i++ ) {
2,092✔
836
                GetThread(i);
1,566✔
837
                WakeupThread(i,TERMINATETHREAD);
1,566✔
838
        }
839
#ifdef WITHSORTBOTS
840
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
1,048✔
841
                WakeupThread(i,TERMINATETHREAD);
522✔
842
        }
843
#endif
844
        for ( i = 1; i <= numberofworkers; i++ ) {
2,092✔
845
                pthread_join(threadpointers[i],NULL);
1,566✔
846
        }
847
#ifdef WITHSORTBOTS
848
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
1,048✔
849
                pthread_join(threadpointers[i],NULL);
522✔
850
        }
851
#endif
852
}
526✔
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)
588✔
884
{
885
        int i;
588✔
886
        LONG sizethreadbuckets;
588✔
887
        THREADBUCKET *thr;
588✔
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);
588✔
895
        if ( AC.ThreadBucketSize >= 250 )      sizethreadbuckets /= 4;
588✔
896
        else if ( AC.ThreadBucketSize >= 90 )  sizethreadbuckets /= 3;
4✔
897
        else if ( AC.ThreadBucketSize >= 40 )  sizethreadbuckets /= 2;
4✔
898
        sizethreadbuckets /= sizeof(WORD);
588✔
899
        
900
        if ( par == 0 ) {
588✔
901
                numthreadbuckets = 2*(number-1);
588✔
902
                threadbuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
588✔
903
                freebuckets = (THREADBUCKET **)Malloc1(numthreadbuckets*sizeof(THREADBUCKET *),"threadbuckets");
588✔
904
        }
905
        if ( par > 0 ) {
588✔
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++ ) {
4,092✔
914
                        threadbuckets[i] = (THREADBUCKET *)Malloc1(sizeof(THREADBUCKET),"threadbuckets");
3,504✔
915
                        threadbuckets[i]->lock = dummylock;
3,504✔
916
                }
917
        }
918
        for ( i = 0; i < numthreadbuckets; i++ ) {
4,092✔
919
                thr = threadbuckets[i];
3,504✔
920
                thr->threadbuffersize = sizethreadbuckets;
3,504✔
921
                thr->free = BUCKETFREE;
3,504✔
922
                thr->deferbuffer = (POSITION *)Malloc1(2*sizethreadbuckets*sizeof(WORD)
7,008✔
923
                                        +(AC.ThreadBucketSize+1)*sizeof(POSITION),"deferbuffer");
3,504✔
924
                thr->threadbuffer = (WORD *)(thr->deferbuffer+AC.ThreadBucketSize+1);
3,504✔
925
                thr->compressbuffer = (WORD *)(thr->threadbuffer+sizethreadbuckets);
3,504✔
926
                thr->busy = BUCKETPREPARINGTERM;
3,504✔
927
                thr->usenum = thr->totnum = 0;
3,504✔
928
                thr->type = BUCKETDOINGTERMS;
3,504✔
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)
1,172✔
987
{
988
        LONG retval = 0;
1,172✔
989
        int i;
1,172✔
990
        for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
4,670✔
991
#ifdef WITHSORTBOTS
992
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ )
2,338✔
993
                retval += timerinfo[i] + sumtimerinfo[i];
1,166✔
994
#endif
995
        return(retval);
1,172✔
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)
5,712✔
1009
{
1010
        ALLPRIVATES *B = AB[identity], *B0 = AB[0];
5,712✔
1011
        AR.GetFile = AR0.GetFile;
5,712✔
1012
        AR.KeptInHold = AR0.KeptInHold;
5,712✔
1013
        AR.CurExpr = AR0.CurExpr;
5,712✔
1014
        AR.SortType = AC.SortType;
5,712✔
1015
        if ( AT.WildcardBufferSize < AC.WildcardBufferSize ) {
5,712✔
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)
6,006✔
1043
{
1044
        WORD *t1, *t2;
6,006✔
1045
        ALLPRIVATES *B = AB[identity], *B0 = AB[from];
6,006✔
1046

1047
        AR.DefPosition = AR0.DefPosition;
6,006✔
1048
        AR.NoCompress = AR0.NoCompress;
6,006✔
1049
        AR.gzipCompress = AR0.gzipCompress;
6,006✔
1050
        AR.BracketOn = AR0.BracketOn;
6,006✔
1051
        AR.CurDum = AR0.CurDum;
6,006✔
1052
        AR.DeferFlag = AR0.DeferFlag;
6,006✔
1053
        AR.TePos = 0;
6,006✔
1054
        AR.sLevel = AR0.sLevel;
6,006✔
1055
        AR.Stage4Name = AR0.Stage4Name;
6,006✔
1056
        AR.GetOneFile = AR0.GetOneFile;
6,006✔
1057
        AR.PolyFun = AR0.PolyFun;
6,006✔
1058
        AR.PolyFunInv = AR0.PolyFunInv;
6,006✔
1059
        AR.PolyFunType = AR0.PolyFunType;
6,006✔
1060
        AR.PolyFunExp = AR0.PolyFunExp;
6,006✔
1061
        AR.PolyFunVar = AR0.PolyFunVar;
6,006✔
1062
        AR.PolyFunPow = AR0.PolyFunPow;
6,006✔
1063
        AR.Eside = AR0.Eside;
6,006✔
1064
        AR.Cnumlhs = AR0.Cnumlhs;
6,006✔
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 ) {
6,006✔
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;
6,006✔
1083
        }
1084
        if ( AR.DeferFlag ) {
6,006✔
1085
                if ( AR.infile->handle < 0 ) {
62✔
1086
                        AR.infile->POfill = AR0.infile->POfill;
4✔
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;
58✔
1094
                }
1095
        }
1096
        if ( par == 0 ) {
6,006✔
1097
                AN.threadbuck = thr;
6,004✔
1098
                AN.ninterms = thr->firstterm;
6,004✔
1099
        }
1100
        else if ( par == 1 ) {
2✔
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;
6,006✔
1108
        AN.ncmod = AC.ncmod;
6,006✔
1109
        AT.BrackBuf = AT0.BrackBuf;
6,006✔
1110
        AT.bracketindexflag = AT0.bracketindexflag;
6,006✔
1111
        AN.PolyFunTodo = 0;
6,006✔
1112
/*
1113
        The relevant variables and the term are in their place.
1114
        There is nothing more to do.
1115
*/
1116
        return(0);
6,006✔
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)
1,972✔
1177
{
1178
        int id;
1,972✔
1179
        ALLPRIVATES *B, *B0 = AB[0];
1,972✔
1180
        for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
7,888✔
1181
                B = AB[id];
5,916✔
1182
                AR.infile = &(AR.Fscr[0]);
5,916✔
1183
                AR.outfile = &(AR.Fscr[1]);
5,916✔
1184
                AR.hidefile = &(AR.Fscr[2]);
5,916✔
1185
                AR.infile->handle = AR0.infile->handle;
5,916✔
1186
                AR.hidefile->handle = AR0.hidefile->handle;
5,916✔
1187
                if ( AR.infile->handle < 0 ) {
5,916✔
1188
                        AR.infile->PObuffer = AR0.infile->PObuffer;
5,880✔
1189
                        AR.infile->POstop = AR0.infile->POstop;
5,880✔
1190
                        AR.infile->POfill = AR0.infile->POfill;
5,880✔
1191
                        AR.infile->POfull = AR0.infile->POfull;
5,880✔
1192
                        AR.infile->POsize = AR0.infile->POsize;
5,880✔
1193
                        AR.InInBuf = AR0.InInBuf;
5,880✔
1194
                        AR.infile->POposition = AR0.infile->POposition;
5,880✔
1195
                        AR.infile->filesize = AR0.infile->filesize;
5,880✔
1196
                }
1197
                else {
1198
                        AR.infile->PObuffer = AR.infile->wPObuffer;
36✔
1199
                        AR.infile->POstop = AR.infile->wPOstop;
36✔
1200
                        AR.infile->POfill = AR.infile->wPOfill;
36✔
1201
                        AR.infile->POfull = AR.infile->wPOfull;
36✔
1202
                        AR.infile->POsize = AR.infile->wPOsize;
36✔
1203
                        AR.InInBuf = 0;
36✔
1204
                        PUTZERO(AR.infile->POposition);
36✔
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;
5,916✔
1213
                        AR.outfile->POstop = AR.outfile->wPOstop;
5,916✔
1214
                        AR.outfile->POfill = AR.outfile->wPOfill;
5,916✔
1215
                        AR.outfile->POfull = AR.outfile->wPOfull;
5,916✔
1216
                        AR.outfile->POsize = AR.outfile->wPOsize;
5,916✔
1217
                        PUTZERO(AR.outfile->POposition);
5,916✔
1218
                }
1219
                if ( AR.hidefile->handle < 0 ) {
5,916✔
1220
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
5,916✔
1221
                        AR.hidefile->POstop = AR0.hidefile->POstop;
5,916✔
1222
                        AR.hidefile->POfill = AR0.hidefile->POfill;
5,916✔
1223
                        AR.hidefile->POfull = AR0.hidefile->POfull;
5,916✔
1224
                        AR.hidefile->POsize = AR0.hidefile->POsize;
5,916✔
1225
                        AR.InHiBuf = AR0.InHiBuf;
5,916✔
1226
                        AR.hidefile->POposition = AR0.hidefile->POposition;
5,916✔
1227
                        AR.hidefile->filesize = AR0.hidefile->filesize;
5,916✔
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 ) {
1,972✔
1240
                for ( id = 1; id < AM.totalnumberofthreads; id++ ) {
×
1241
                        B = AB[id];
×
1242
                        AR.StoreData = AR0.StoreData;
×
1243
                }
1244
        }
1245
}
1,972✔
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)
1,752✔
1259
{
1260
        WORD *term, *ttin, *tt, *ttco, *oldwork;
1,752✔
1261
        int identity, wakeupsignal, identityretv, i, tobereleased, errorcode;
1,752✔
1262
        ALLPRIVATES *B;
1,752✔
1263
        THREADBUCKET *thr;
1,752✔
1264
        POSITION *ppdef;
1,752✔
1265
        EXPRESSIONS e;
1,752✔
1266
        DUMMYUSE(dummy);
1,752✔
1267
        identity = SetIdentity(&identityretv);
1,752✔
1268
        threadpointers[identity] = pthread_self();
1,752✔
1269
        B = InitializeOneThread(identity);
1,752✔
1270
        while ( ( wakeupsignal = ThreadWait(identity) ) > 0 ) {
24,707✔
1271
                switch ( wakeupsignal ) {
22,999✔
1272
/*
1273
                        #[ STARTNEWEXPRESSION :
1274
*/
1275
                        case STARTNEWEXPRESSION:
5,712✔
1276
/*
1277
                                Set up the sort routines etc.
1278
                                Start with getting some buffers synchronized with the compiler
1279
*/
1280
                                if ( UpdateOneThread(identity) ) {
5,712✔
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;
5,712✔
1287
                                AR.sLevel = AS.sLevel;
5,712✔
1288
                                AR.MaxDum = AM.IndDum;
5,712✔
1289
                                AR.expchanged = AB[0]->R.expchanged;
5,712✔
1290
                                AR.expflags = AB[0]->R.expflags;
5,712✔
1291
                                AR.PolyFun = AB[0]->R.PolyFun;
5,712✔
1292
                                AR.PolyFunInv = AB[0]->R.PolyFunInv;
5,712✔
1293
                                AR.PolyFunType = AB[0]->R.PolyFunType;
5,712✔
1294
                                AR.PolyFunExp = AB[0]->R.PolyFunExp;
5,712✔
1295
                                AR.PolyFunVar = AB[0]->R.PolyFunVar;
5,712✔
1296
                                AR.PolyFunPow = AB[0]->R.PolyFunPow;
5,712✔
1297
/*
1298
                                Now fire up the sort buffer.
1299
*/
1300
                                NewSort(BHEAD0);
5,712✔
1301
                                break;
5,712✔
1302
/*
1303
                        #] STARTNEWEXPRESSION : 
1304
                        #[ LOWESTLEVELGENERATION :
1305
*/
1306
                        case LOWESTLEVELGENERATION:
5,951✔
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;
5,951✔
1315
                                thr = AN.threadbuck;
5,951✔
1316
                                ppdef = thr->deferbuffer;
5,951✔
1317
                                ttin = thr->threadbuffer;
5,951✔
1318
                                ttco = thr->compressbuffer;
5,951✔
1319
                                term = AT.WorkPointer;
5,951✔
1320
                                thr->usenum = 0;
5,951✔
1321
                                tobereleased = 0;
5,951✔
1322
                                AN.inputnumber = thr->firstterm;
5,951✔
1323
                                AN.ninterms = thr->firstterm;
5,951✔
1324
                                do {
347,936✔
1325
                                  thr->usenum++;        /* For if the master wants to steal the bucket */
347,936✔
1326
                                  tt = term; i = *ttin;
347,936✔
1327
                                  NCOPY(tt,ttin,i);
14,963,804✔
1328
                                  AT.WorkPointer = tt;
347,936✔
1329
                                  if ( AR.DeferFlag ) {
347,936✔
1330
                                        tt = AR.CompressBuffer; i = *ttco;
206✔
1331
                                        NCOPY(tt,ttco,i);
6,720✔
1332
                                        AR.CompressPointer = tt;
206✔
1333
                                        AR.DefPosition = ppdef[0]; ppdef++;
206✔
1334
                                  }
1335
                                  if ( thr->free == BUCKETTERMINATED ) {
347,936✔
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);
347,936✔
1357
                                        thr->busy = BUCKETDOINGTERM;
347,936✔
1358
                                        UNLOCK(thr->lock);
347,936✔
1359
/*
1360
                                  }
1361
                                  else {
1362
                                        thr->busy = BUCKETDOINGTERM;
1363
                                  }
1364
*/
1365
                                  AN.RepPoint = AT.RepCount + 1;
347,936✔
1366

1367
                                  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
347,936✔
1368
                                    StoreTerm(BHEAD term);
×
1369
                                  }
1370
                                  else {
1371
                                  if ( AR.DeferFlag ) {
347,936✔
1372
                                        AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
206✔
1373
                                  }
1374
                                  else {
1375
                                        AN.IndDum = AM.IndDum;
347,730✔
1376
                                        AR.CurDum = ReNumber(BHEAD term);
347,730✔
1377
                                  }
1378
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
347,936✔
1379
                                  if ( AN.ncmod ) {
347,936✔
1380
                                        if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
2✔
1381
                                        else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
2✔
1382
                                  }
1383
                                  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
347,934✔
1384
                                  if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
347,936✔
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 )
347,936✔
1391
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
2,276✔
1392
                                                PolyFunClean(BHEAD term);
2,276✔
1393
                                  }
1394
                                  if ( Generator(BHEAD term,0) ) {
347,936✔
1395
                                        LowerSortLevel();
4✔
1396
                                        MLOCK(ErrorMessageLock);
4✔
1397
                                        MesPrint("Error in processing one term in thread %d in module %d",identity,AC.CModule);
4✔
1398
                                        MUNLOCK(ErrorMessageLock);
4✔
1399
                                        Terminate(-1);
4✔
1400
                                  }
1401
                                  AN.ninterms++;
347,898✔
1402
                                  }
1403
/*                                  if ( AT.LoadBalancing ) { */
1404
                                        LOCK(thr->lock);
347,898✔
1405
                                        thr->busy = BUCKETPREPARINGTERM;
347,898✔
1406
                                        UNLOCK(thr->lock);
347,898✔
1407
/*
1408
                                  }
1409
                                  else {
1410
                                        thr->busy = BUCKETPREPARINGTERM;
1411
                                  }
1412
*/
1413
                                  if ( thr->free == BUCKETTERMINATED ) {
347,898✔
1414
                                        if ( thr->usenum == thr->totnum ) {
88✔
1415
                                                thr->free = BUCKETCOMINGFREE;
×
1416
                                        }
1417
                                        else {
1418
                                                thr->free = BUCKETRELEASED;
88✔
1419
                                                tobereleased = 1;
88✔
1420
                                        }
1421
                                  }
1422
                                  if ( tobereleased ) goto bucketstolen;
347,898✔
1423
                                } while ( *ttin );
347,810✔
1424
                                thr->free = BUCKETCOMINGFREE;
5,825✔
1425
bucketstolen:;
5,913✔
1426
/*                                if ( AT.LoadBalancing ) { */
1427
                                        LOCK(thr->lock);
5,913✔
1428
                                        thr->busy = BUCKETTOBERELEASED;
5,913✔
1429
                                        UNLOCK(thr->lock);
5,913✔
1430
/*                                }
1431
                                else {
1432
                                        thr->busy = BUCKETTOBERELEASED;
1433
                                }
1434
*/
1435
                                AT.WorkPointer = term;
5,913✔
1436
                                break;
5,913✔
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:
5,598✔
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]);
5,598✔
1455
                                ThreadClaimedBlock(identity);
5,598✔
1456
/*
1457
                                Entry for when we work with sortbots
1458
*/
1459
#ifdef WITHSORTBOTS
1460
                                /* fall through */
1461
                        case FINISHEXPRESSION2:
5,598✔
1462
#endif
1463
/*
1464
                                Now we may need here an fsync on the sort file
1465
*/
1466
                                if ( AC.ThreadSortFileSynch ) {
5,598✔
1467
                                  if ( AT.S0->file.handle >= 0 ) {
×
1468
                                        SynchFile(AT.S0->file.handle);
×
1469
                                  }
1470
                                }
1471
                                AT.SB.FillBlock = 1;
5,598✔
1472
                                AT.SB.MasterFill[1] = AT.SB.MasterStart[1];
5,598✔
1473
                                errorcode = EndSort(BHEAD AT.S0->sBuffer,0);
5,598✔
1474
                                UNLOCK(AT.SB.MasterBlockLock[AT.SB.FillBlock]);
5,592✔
1475
                                UpdateMaxSize();
5,592✔
1476
                                if ( errorcode ) {
5,592✔
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:
5,592✔
1488
/*
1489
                                Cleanup everything and wait for the next expression
1490
*/
1491
                                if ( AR.outfile->handle >= 0 ) {
5,592✔
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;
5,592✔
1501
                                        PUTZERO(AR.outfile->POposition);
5,592✔
1502
                                        PUTZERO(AR.outfile->filesize);
5,592✔
1503
                                }
1504
                                {
1505
                                        CBUF *C = cbuf+AT.ebufnum;
5,592✔
1506
                                        WORD **w, ii;
5,592✔
1507
                                        if ( C->numrhs > 0 || C->numlhs > 0 ) {
5,592✔
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: {
2✔
1574

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

1593
                                position = AS.OldOnFile[i];
2✔
1594
                                if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION ) {
2✔
1595
                                        AR.GetFile = 2; fi = AR.hidefile;
×
1596
                                }
1597
                                else {
1598
                                        AR.GetFile = 0; fi = AR.infile;
2✔
1599
                                }
1600
/*
1601
                                PUTZERO(fi->POposition);
1602
                                if ( fi->handle >= 0 ) {
1603
                                        fi->POfill = fi->POfull = fi->PObuffer;
1604
                                }
1605
*/
1606
                                SetScratch(fi,&position);
2✔
1607
                                term = oldwork = AT.WorkPointer;
2✔
1608
                                AR.CompressPointer = AR.CompressBuffer;
2✔
1609
                                AR.CompressPointer[0] = 0;
2✔
1610
                                AR.KeptInHold = 0;
2✔
1611
                                if ( GetTerm(BHEAD term) <= 0 ) {
2✔
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);
2✔
1618
                                term[3] = i;
2✔
1619
                                if ( term[5] < 0 ) {
2✔
1620
                                        fromspectator = -term[5];
×
1621
                                        PUTZERO(AM.SpectatorFiles[fromspectator-1].readpos);
×
1622
                                        term[5] = AC.cbufnum;
×
1623
                                }
1624
                                PUTZERO(outposition);
2✔
1625
                                fout = AR.outfile;
2✔
1626
                                fout->POfill = fout->POfull = fout->PObuffer;
2✔
1627
                                fout->POposition = outposition;
2✔
1628
                                if ( fout->handle >= 0 ) {
2✔
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);
2✔
1641
                                if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) goto ProcErr;
2✔
1642

1643
                                AR.DeferFlag = AC.ComDefer;
2✔
1644

1645
                                AR.sLevel = AB[0]->R.sLevel;
2✔
1646
                                term = AT.WorkPointer;
2✔
1647
                                NewSort(BHEAD0);
2✔
1648
                                AR.MaxDum = AM.IndDum;
2✔
1649
                                AN.ninterms = 0;
2✔
1650
                                if ( fromspectator ) {
2✔
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) ) {
4✔
1673
                                  SeekScratch(fi,&position);
2✔
1674
                                  AN.ninterms++; dd = AN.deferskipped;
2✔
1675
                                  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
2✔
1676
                                          StoreTerm(BHEAD term);
×
1677
                                  }
1678
                                  else {
1679
                                  if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
2✔
1680
                                        if ( GetMoreTerms(term) < 0 ) {
×
1681
                                          LowerSortLevel(); goto ProcErr;
×
1682
                                        }
1683
                                    SeekScratch(fi,&position);
×
1684
                                  }
1685
                                  AT.WorkPointer = term + *term;
2✔
1686
                                  AN.RepPoint = AT.RepCount + 1;
2✔
1687
                                  if ( AR.DeferFlag ) {
2✔
1688
                                        AR.CurDum = AN.IndDum = Expressions[AR.exprtodo].numdummies;
×
1689
                                  }
1690
                                  else {
1691
                                        AN.IndDum = AM.IndDum;
2✔
1692
                                        AR.CurDum = ReNumber(BHEAD term);
2✔
1693
                                  }
1694
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
2✔
1695
                                  if ( AN.ncmod ) {
2✔
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);
2✔
1700
                                  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
2✔
1701
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
×
1702
                                                PolyFunClean(BHEAD term);
×
1703
                                  }
1704
                                  if ( Generator(BHEAD term,0) ) {
2✔
1705
                                        LowerSortLevel(); goto ProcErr;
×
1706
                                  }
1707
                                  AN.ninterms += dd;
2✔
1708
                                  }
1709
                                  SetScratch(fi,&position);
2✔
1710
                                  if ( fi == AR.hidefile ) {
2✔
1711
                                        AR.InHiBuf = (fi->POfull-fi->PObuffer)
×
1712
                                                -DIFBASE(position,fi->POposition)/sizeof(WORD);
×
1713
                                  }
1714
                                  else {
1715
                                        AR.InInBuf = (fi->POfull-fi->PObuffer)
2✔
1716
                                                -DIFBASE(position,fi->POposition)/sizeof(WORD);
2✔
1717
                                  }
1718
                                 }
1719
                                }
1720
                                AN.ninterms += dd;
2✔
1721
                                if ( EndSort(BHEAD AT.S0->sBuffer,0) < 0 ) goto ProcErr;
2✔
1722
                                e->numdummies = AR.MaxDum - AM.IndDum;
2✔
1723
                                AR.BracketOn = oldBracketOn;
2✔
1724
                                AT.BrackBuf = oldBrackBuf;
2✔
1725
                                if ( ( e->vflags & TOBEFACTORED ) != 0 )
2✔
1726
                                                poly_factorize_expression(e);
×
1727
                                else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
2✔
1728
                                 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
2✔
1729
                                                poly_unfactorize_expression(e);
×
1730
                                if ( AT.S0->TermsLeft )   e->vflags &= ~ISZERO;
2✔
1731
                                else                      e->vflags |= ISZERO;
×
1732
                                if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
2✔
1733
                                if ( AT.S0->TermsLeft ) AR.expflags |= ISZERO;
2✔
1734
                                if ( AR.expchanged )    AR.expflags |= ISUNMODIFIED;
2✔
1735
                                AR.GetFile = 0;
2✔
1736
                                AT.bracketindexflag = oldbracketindexflag;
2✔
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);
2✔
1742
                                LOCK(AS.outputslock);
2✔
1743
                                oldoutfile = AB[0]->R.outfile;
2✔
1744
                                if ( e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
2✔
1745
                                        AB[0]->R.outfile = AB[0]->R.hidefile;
×
1746
                                }
1747
                                SeekScratch(AB[0]->R.outfile,&position);
2✔
1748
                                e->onfile = position;
2✔
1749
                                if ( CopyExpression(fout,AB[0]->R.outfile) < 0 ) {
2✔
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;
2✔
1758
                                AB[0]->R.hidefile->POfull = AB[0]->R.hidefile->POfill;
2✔
1759
                                AB[0]->R.expflags = AR.expflags;
2✔
1760
                                UNLOCK(AS.outputslock);
2✔
1761

1762
                                if ( fout->handle >= 0 ) {        /* Now get rid of the file */
2✔
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();
2✔
1771

1772
                                AT.WorkPointer = oldwork;
2✔
1773

1774
                                } break;
2✔
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: {
53✔
1792
                                BRACKETINFO *binfo;
53✔
1793
                                BRACKETINDEX *bi;
53✔
1794
                                FILEHANDLE *fi;
53✔
1795
                                POSITION stoppos,where;
53✔
1796
                                e = Expressions + AR.CurExpr;
53✔
1797
                                binfo = e->bracketinfo;
53✔
1798
                                thr = AN.threadbuck;
53✔
1799
                                bi = &(binfo->indexbuffer[thr->firstbracket]);
53✔
1800
                                if ( AR.GetFile == 2 ) fi = AR.hidefile;
53✔
1801
                                else                   fi = AR.infile;
53✔
1802
                                where = bi->start;
53✔
1803
                                ADD2POS(where,AS.OldOnFile[AR.CurExpr]);
53✔
1804
                                SetScratch(fi,&(where));
53✔
1805
                                stoppos = binfo->indexbuffer[thr->lastbracket].next;
53✔
1806
                                ADD2POS(stoppos,AS.OldOnFile[AR.CurExpr]);
53✔
1807
                                AN.ninterms = thr->firstterm;
53✔
1808
/*
1809
                                Now we have to put the 'value' of the bracket in the
1810
                                Compress buffer.
1811
*/
1812
                                ttco = AR.CompressBuffer;
53✔
1813
                                tt = binfo->bracketbuffer + bi->bracket;
53✔
1814
                                i = *tt;
53✔
1815
                                NCOPY(ttco,tt,i)
687✔
1816
                                AR.CompressPointer = ttco;
53✔
1817
                                term = AT.WorkPointer;
53✔
1818
                                while ( GetTerm(BHEAD term) ) {
18,202✔
1819
                                        SeekScratch(fi,&where);
18,202✔
1820
                                        AT.WorkPointer = term + *term;
18,202✔
1821
                                        AN.IndDum = AM.IndDum;
18,202✔
1822
                                        AR.CurDum = ReNumber(BHEAD term);
18,202✔
1823
                                        if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
18,202✔
1824
                                        if ( AN.ncmod ) {
18,202✔
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);
18,202✔
1829
                                        if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
18,202✔
1830
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
×
1831
                                                PolyFunClean(BHEAD term);
×
1832
                                        }
1833
                                        if ( ( AP.PreDebug & THREADSDEBUG ) != 0 ) {
18,202✔
1834
                                                MLOCK(ErrorMessageLock);
×
1835
                                                MesPrint("Thread %w executing term:");
×
1836
                                                PrintTerm(term,"DoBrackets");
×
1837
                                                MUNLOCK(ErrorMessageLock);
×
1838
                                        }
1839
                                        AT.WorkPointer = term + *term;
18,202✔
1840
                                        if ( Generator(BHEAD term,0) ) {
18,202✔
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++;
18,202✔
1848
                                        SetScratch(fi,&(where));
18,202✔
1849
                                        if ( ISGEPOS(where,stoppos) ) break;
18,202✔
1850
                                }
1851
                                AT.WorkPointer = term;
53✔
1852
                                thr->free = BUCKETCOMINGFREE;
53✔
1853
                                break;
53✔
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:
61✔
1872
                                AT.optimtimes = AB[0]->T.optimtimes;
61✔
1873
                                find_Horner_MCTS_expand_tree();
61✔
1874
                                break;
61✔
1875
/*
1876
                        #] MCTSEXPANDTREE : 
1877
                        #[ OPTIMIZEEXPRESSION :
1878
*/
1879
                        case OPTIMIZEEXPRESSION:
30✔
1880
                                optimize_expression_given_Horner();
30✔
1881
                                break;
30✔
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);
22,955✔
1895
        }
1896
EndOfThread:;
1,566✔
1897
/*
1898
        This is the end of the thread. We cleanup and exit.
1899
*/
1900
        FinalizeOneThread(identity);
1,566✔
1901
        return(0);
1,566✔
1902
ProcErr:
×
1903
        Terminate(-1);
×
1904
        return(0);
×
1905
}
1906

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

1918
#ifdef WITHSORTBOTS
1919

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

1980
                        The program only comes here after a .clear
1981
*/
1982
                        case CLEARCLOCK:
×
1983
/*                                LOCK(clearclocklock); */
1984
                                sumtimerinfo[identity] += TimeCPU(1);
×
1985
                                timerinfo[identity] = TimeCPU(0);
×
1986
/*                                UNLOCK(clearclocklock); */
1987
                                break;
×
1988
/*
1989
                        #] CLEARCLOCK : 
1990
*/
1991
                        default:
×
1992
                                MLOCK(ErrorMessageLock);
×
1993
                                MesPrint("Illegal wakeup signal %d for thread %d",wakeupsignal,identity);
×
1994
                                MUNLOCK(ErrorMessageLock);
×
1995
                                Terminate(-1);
×
1996
                                break;
×
1997
                }
1998
        }
1999
EndOfThread:;
522✔
2000
/*
2001
        This is the end of the thread. We cleanup and exit.
2002
*/
2003
        FinalizeOneThread(identity);
522✔
2004
        return(0);
522✔
2005
}
2006

2007
#endif
2008

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

2024
void IAmAvailable(int identity)
×
2025
{
2026
        int top;
×
2027
        LOCK(availabilitylock);
×
2028
        top = topofavailables;
×
2029
        listofavailables[topofavailables++] = identity;
×
2030
        if ( top == 0 ) {
×
2031
                UNLOCK(availabilitylock);
×
2032
                LOCK(wakeupmasterlock);
×
2033
                wakeupmaster = identity;
×
2034
                pthread_cond_signal(&wakeupmasterconditions);
×
2035
                UNLOCK(wakeupmasterlock);
×
2036
        }
2037
        else {
2038
                UNLOCK(availabilitylock);
×
2039
        }
2040
}
×
2041

2042
/*
2043
          #] IAmAvailable : 
2044
          #[ GetAvailableThread :
2045
*/
2046
/**
2047
 *        Gets an available thread from the top of the stack.
2048
 *        Maybe a circular buffer model would work better. This would mean that
2049
 *        we take the lowest available worker, rather than the highest.
2050
 *        We then have to work with high water marks and low water marks.
2051
 *        (writing point and reading point). Still to be investigated.
2052
 */
2053

2054
int GetAvailableThread(VOID)
8,651✔
2055
{
2056
        int retval = -1;
8,651✔
2057
        LOCK(availabilitylock);
8,651✔
2058
        if ( topofavailables > 0 ) retval = listofavailables[--topofavailables];
8,651✔
2059
        UNLOCK(availabilitylock);
8,651✔
2060
        if ( retval >= 0 ) {
8,651✔
2061
/*
2062
                Make sure the thread is indeed waiting and not between
2063
                saying that it is available and starting to wait.
2064
*/
2065
                LOCK(wakeuplocks[retval]);
6,097✔
2066
                UNLOCK(wakeuplocks[retval]);
6,097✔
2067
        }
2068
        return(retval);
8,651✔
2069
}
2070

2071
/*
2072
          #] GetAvailableThread : 
2073
          #[ ConditionalGetAvailableThread :
2074
*/
2075
/**
2076
 *        Looks whether a thread is available.
2077
 *        If a thread is available it is taken from the stack of available threads.
2078
 *
2079
 *        @return the identity of an available thread or -1 if none is available.
2080
 */
2081

2082
int ConditionalGetAvailableThread(VOID)
×
2083
{
2084
        int retval = -1;
×
2085
        if ( topofavailables > 0 ) {
×
2086
                LOCK(availabilitylock);
×
2087
                if ( topofavailables > 0 ) {
×
2088
                        retval = listofavailables[--topofavailables];
×
2089
                }
2090
                UNLOCK(availabilitylock);
×
2091
                if ( retval >= 0 ) {
×
2092
/*
2093
                        Make sure the thread is indeed waiting and not between
2094
                        saying that it is available and starting to wait.
2095
*/
2096
                        LOCK(wakeuplocks[retval]);
×
2097
                        UNLOCK(wakeuplocks[retval]);
×
2098
                }
2099
        }
2100
        return(retval);
×
2101
}
2102

2103
/*
2104
          #] ConditionalGetAvailableThread : 
2105
          #[ GetThread :
2106
*/
2107
/**
2108
 *        Gets a given thread from the list of available threads, even if
2109
 *        it isn't on the top of the stack.
2110
 *
2111
 *        @param identity The number of the thread that we want to remove from the
2112
 *                        list of available threads.
2113
 *        @return The number of the thread if it was available. -1 otherwise.
2114
 */
2115

2116
int GetThread(int identity)
12,756✔
2117
{
2118
        int retval = -1, j;
12,756✔
2119
        LOCK(availabilitylock);
12,756✔
2120
        for ( j = 0; j < topofavailables; j++ ) {
36,179✔
2121
                if ( identity == listofavailables[j] ) break;
23,423✔
2122
        }
2123
        if ( j < topofavailables ) {
12,756✔
2124
                --topofavailables;
12,756✔
2125
                for ( ; j < topofavailables; j++ ) {
17,134✔
2126
                        listofavailables[j] = listofavailables[j+1];
4,378✔
2127
                }
2128
                retval = identity;
2129
        }
2130
        UNLOCK(availabilitylock);
12,756✔
2131
        return(retval);
12,756✔
2132
}
2133

2134
/*
2135
          #] GetThread : 
2136
          #[ ThreadWait :
2137
*/
2138
/**
2139
 *        To be called by a thread when it has nothing to do.
2140
 *        It goes to sleep and waits for a wakeup call.
2141
 *        The return value is the number of the wakeup signal.
2142
 *
2143
 *        @param identity The number of the thread.
2144
 *        @return The number of the wake-up signal.
2145
 */
2146

2147
int ThreadWait(int identity)
24,707✔
2148
{
2149
        int retval, top, j;
24,707✔
2150
        LOCK(wakeuplocks[identity]);
24,707✔
2151
        LOCK(availabilitylock);
24,707✔
2152
        top = topofavailables;
24,707✔
2153
        for ( j = topofavailables; j > 0; j-- )
52,225✔
2154
                listofavailables[j] = listofavailables[j-1];
27,518✔
2155
        listofavailables[0] = identity;
24,707✔
2156
        topofavailables++;
24,707✔
2157
        if ( top == 0 || topofavailables == numberofworkers ) {
24,707✔
2158
                UNLOCK(availabilitylock);
17,411✔
2159
                LOCK(wakeupmasterlock);
17,411✔
2160
                wakeupmaster = identity;
17,411✔
2161
                pthread_cond_signal(&wakeupmasterconditions);
17,411✔
2162
                UNLOCK(wakeupmasterlock);
17,411✔
2163
        }
2164
        else {
2165
                UNLOCK(availabilitylock);
7,296✔
2166
        }
2167
        while ( wakeup[identity] == 0 ) {
49,272✔
2168
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
24,707✔
2169
        }
2170
        retval = wakeup[identity];
24,565✔
2171
        wakeup[identity] = 0;
24,565✔
2172
        UNLOCK(wakeuplocks[identity]);
24,565✔
2173
        return(retval);
24,565✔
2174
}
2175

2176
/*
2177
          #] ThreadWait : 
2178
          #[ SortBotWait :
2179
*/
2180
 
2181
#ifdef WITHSORTBOTS
2182
/**
2183
 *        To be called by a sortbot thread when it has nothing to do.
2184
 *        It goes to sleep and waits for a wakeup call.
2185
 *        The return value is the number of the wakeup signal.
2186
 *
2187
 *        @param identity The number of the sortbot thread.
2188
 *        @return The number of the wake-up signal.
2189
 */
2190

2191
int SortBotWait(int identity)
4,314✔
2192
{
2193
        int retval;
4,314✔
2194
        LOCK(wakeuplocks[identity]);
4,314✔
2195
        LOCK(availabilitylock);
4,314✔
2196
        topsortbotavailables++;
4,314✔
2197
        if ( topsortbotavailables >= numberofsortbots ) {
4,314✔
2198
                UNLOCK(availabilitylock);
2,157✔
2199
                LOCK(wakeupsortbotlock);
2,157✔
2200
                wakeupmaster = identity;
2,157✔
2201
                pthread_cond_signal(&wakeupsortbotconditions);
2,157✔
2202
                UNLOCK(wakeupsortbotlock);
2,157✔
2203
        }
2204
        else {
2205
                UNLOCK(availabilitylock);
2,157✔
2206
        }
2207
        while ( wakeup[identity] == 0 ) {
8,568✔
2208
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
4,314✔
2209
        }
2210
        retval = wakeup[identity];
4,254✔
2211
        wakeup[identity] = 0;
4,254✔
2212
        UNLOCK(wakeuplocks[identity]);
4,254✔
2213
        return(retval);
4,254✔
2214
}
2215

2216
#endif
2217

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

2232
int ThreadClaimedBlock(int identity)
5,598✔
2233
{
2234
        LOCK(availabilitylock);
5,598✔
2235
        numberclaimed++;        
5,598✔
2236
        if ( numberclaimed >= numberofworkers ) {
5,598✔
2237
                UNLOCK(availabilitylock);
1,866✔
2238
                LOCK(wakeupmasterlock);
1,866✔
2239
                wakeupmaster = identity;
1,866✔
2240
                pthread_cond_signal(&wakeupmasterconditions);
1,866✔
2241
                UNLOCK(wakeupmasterlock);
1,866✔
2242
        }
2243
        else {
2244
                UNLOCK(availabilitylock);
3,732✔
2245
        }
2246
        return(0);
5,598✔
2247
}
2248

2249
/*
2250
          #] ThreadClaimedBlock : 
2251
          #[ MasterWait :
2252
*/
2253
/**
2254
 *        To be called by the master when it has to wait for one of the
2255
 *        workers to become available.
2256
 *        It goes to sleep and waits for a wakeupmaster call.
2257
 *        The return value is the identity of the process that wakes up the master.
2258
 */
2259

2260
int MasterWait(VOID)
2,847✔
2261
{
2262
        int retval;
2,847✔
2263
        LOCK(wakeupmasterlock);
2,847✔
2264
        while ( wakeupmaster == 0 ) {
5,097✔
2265
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2,250✔
2266
        }
2267
        retval = wakeupmaster;
2,847✔
2268
        wakeupmaster = 0;
2,847✔
2269
        UNLOCK(wakeupmasterlock);
2,847✔
2270
        return(retval);
2,847✔
2271
}
2272

2273
/*
2274
          #] MasterWait : 
2275
          #[ MasterWaitThread :
2276
*/
2277
/**
2278
 *        To be called by the master when it has to wait for a specific one of the
2279
 *        workers to become available.
2280
 *        The return value is the value of the signal.
2281
 */
2282

2283
int MasterWaitThread(int identity)
×
2284
{
2285
        int retval;
×
2286
        LOCK(wakeupmasterthreadlocks[identity]);
×
2287
        while ( wakeupmasterthread[identity] == 0 ) {
×
2288
                pthread_cond_wait(&(wakeupmasterthreadconditions[identity])
×
2289
                                ,&(wakeupmasterthreadlocks[identity]));
2290
        }
2291
        retval = wakeupmasterthread[identity];
×
2292
        wakeupmasterthread[identity] = 0;
×
2293
        UNLOCK(wakeupmasterthreadlocks[identity]);
×
2294
        return(retval);
×
2295
}
2296

2297
/*
2298
          #] MasterWaitThread : 
2299
          #[ MasterWaitAll :
2300
*/
2301
/**
2302
 *        To be called by the master when it has to wait for all of the
2303
 *        workers to finish a given task.
2304
 *        It goes to sleep and waits for a wakeup call in ThreadWait
2305
 */
2306

2307
void MasterWaitAll(VOID)
8,174✔
2308
{
2309
        LOCK(wakeupmasterlock);
8,174✔
2310
        while ( topofavailables < numberofworkers ) {
15,092✔
2311
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
6,956✔
2312
        }
2313
        UNLOCK(wakeupmasterlock);
8,136✔
2314
        return;
8,136✔
2315
}
2316

2317
/*
2318
          #] MasterWaitAll : 
2319
          #[ MasterWaitAllSortBots :
2320
*/
2321
 
2322
#ifdef WITHSORTBOTS
2323

2324
/**
2325
 *        To be called by the master when it has to wait for all of the
2326
 *        sortbots to start their task.
2327
 */
2328

2329
void MasterWaitAllSortBots(VOID)
2,453✔
2330
{
2331
        LOCK(wakeupsortbotlock);
2,453✔
2332
        while ( topsortbotavailables < numberofsortbots ) {
3,677✔
2333
                pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
1,224✔
2334
        }
2335
        UNLOCK(wakeupsortbotlock);
2,453✔
2336
        return;
2,453✔
2337
}
2338

2339
#endif
2340

2341
/*
2342
          #] MasterWaitAllSortBots : 
2343
          #[ MasterWaitAllBlocks :
2344
*/
2345
/**
2346
 *        To be called by the master when it has to wait for all of the
2347
 *        workers to claim their first block in the sort buffers of the master.
2348
 *        It goes to sleep and waits for a wakeup call.
2349
 */
2350

2351
void MasterWaitAllBlocks(VOID)
1,866✔
2352
{
2353
        LOCK(wakeupmasterlock);
1,866✔
2354
        while ( numberclaimed < numberofworkers ) {
3,957✔
2355
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
2,091✔
2356
        }
2357
        UNLOCK(wakeupmasterlock);
1,866✔
2358
        return;
1,866✔
2359
}
2360

2361
/*
2362
          #] MasterWaitAllBlocks : 
2363
          #[ WakeupThread :
2364
*/
2365
/**
2366
 *        To be called when the indicated thread needs waking up.
2367
 *        The signal number should be nonzero!
2368
 *
2369
 *        @param identity     The number of the worker to be woken up
2370
 *        @param signalnumber The signal with which it should be woken up.
2371
 */
2372

2373
void WakeupThread(int identity, int signalnumber)
28,819✔
2374
{
2375
        if ( signalnumber == 0 ) {
28,819✔
2376
                MLOCK(ErrorMessageLock);
×
2377
                MesPrint("Illegal wakeup signal for thread %d",identity);
×
2378
                MUNLOCK(ErrorMessageLock);
×
2379
                Terminate(-1);
×
2380
        }
2381
        LOCK(wakeuplocks[identity]);
28,819✔
2382
        wakeup[identity] = signalnumber;
28,819✔
2383
        pthread_cond_signal(&(wakeupconditions[identity]));
28,819✔
2384
        UNLOCK(wakeuplocks[identity]);
28,819✔
2385
}
28,819✔
2386

2387
/*
2388
          #] WakeupThread : 
2389
          #[ WakeupMasterFromThread :
2390
*/
2391
/**
2392
 *        To be called when the indicated thread needs to wake up the master.
2393
 *        The signal number should be nonzero!
2394
 *
2395
 *        @param identity     The number of the worker who wakes up the master.
2396
 *        @param signalnumber The signal with which the master should be woken up.
2397
 */
2398

2399
void WakeupMasterFromThread(int identity, int signalnumber)
×
2400
{
2401
        if ( signalnumber == 0 ) {
×
2402
                MLOCK(ErrorMessageLock);
×
2403
                MesPrint("Illegal wakeup signal for master %d",identity);
×
2404
                MUNLOCK(ErrorMessageLock);
×
2405
                Terminate(-1);
×
2406
        }
2407
        LOCK(wakeupmasterthreadlocks[identity]);
×
2408
        wakeupmasterthread[identity] = signalnumber;
×
2409
        pthread_cond_signal(&(wakeupmasterthreadconditions[identity]));
×
2410
        UNLOCK(wakeupmasterthreadlocks[identity]);
×
2411
}
×
2412

2413
/*
2414
          #] WakeupMasterFromThread : 
2415
          #[ SendOneBucket :
2416
*/
2417
/**
2418
 *        To be called when there is a full bucket and an available thread
2419
 *        It prepares the thread and then wakes it up.
2420
 */
2421

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

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

2480
int InParallelProcessor(VOID)
986✔
2481
{
2482
        GETIDENTITY
986✔
2483
        int i, id, retval = 0, num = 0;
986✔
2484
        EXPRESSIONS e;
986✔
2485
        if ( numberofworkers >= 2 ) {
986✔
2486
                SetWorkerFiles();
986✔
2487
                for ( i = 0; i < NumExpressions; i++ ) {
4,212✔
2488
                        e = Expressions+i;
2,240✔
2489
                        if ( e->partodo <= 0 ) continue;
2,240✔
2490
                        if ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION
2✔
2491
                        || e->status == UNHIDELEXPRESSION || e->status == UNHIDEGEXPRESSION
2492
                        || e->status == INTOHIDELEXPRESSION || e->status == INTOHIDEGEXPRESSION ) {
×
2493
                        }
2494
                        else {
2495
                                e->partodo = 0;
×
2496
                                continue;
×
2497
                        }
2498
                        if ( e->counter == 0 ) { /* Expression with zero terms */
2✔
2499
                                e->partodo = 0;
×
2500
                                continue;
×
2501
                        }
2502
/*
2503
                        This expression should go to an idle worker
2504
*/
2505
                        while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
2✔
2506
                        LoadOneThread(0,id,0,-1);
2✔
2507
                        AB[id]->R.exprtodo = i;
2✔
2508
                        WakeupThread(id,DOONEEXPRESSION);
2✔
2509
                        num++;
2✔
2510
                }
2511
/*
2512
                Now we have to wait for all workers to finish
2513
*/
2514
                if ( num > 0 ) MasterWaitAll();
986✔
2515

2516
                if ( AC.CollectFun ) AR.DeferFlag = 0;
986✔
2517
        }
2518
        else {
2519
                for ( i = 0; i < NumExpressions; i++ ) {
×
2520
                        Expressions[i].partodo = 0;
×
2521
                }
2522
        }
2523
        return(retval);
986✔
2524
}
2525

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

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

2573
        AS.sLevel = AR0.sLevel;
1,904✔
2574
        LOCK(availabilitylock);
1,904✔
2575
        topofavailables = 0;
1,904✔
2576
        for ( id = 1; id <= numberofworkers; id++ ) {
7,616✔
2577
                WakeupThread(id,STARTNEWEXPRESSION);
5,712✔
2578
        }
2579
        UNLOCK(availabilitylock);
1,904✔
2580
        NewSort(BHEAD0);
1,904✔
2581
        AN0.ninterms = 1;
1,904✔
2582
/*
2583
        Now for redefine
2584
*/
2585
        if ( AC.numpfirstnum > 0 ) {
1,904✔
2586
                for ( j = 0; j < AC.numpfirstnum; j++ ) {
28✔
2587
                        AC.inputnumbers[j] = -1;
14✔
2588
                }
2589
        }
2590
        MasterWaitAll();
1,904✔
2591
/*
2592
        Determine a reasonable bucketsize.
2593
        This is based on the value of AC.ThreadBucketSize and the number
2594
        of terms. We want at least 5 buckets per worker at the moment.
2595
        Some research should show whether this is reasonable.
2596

2597
        The number of terms in the expression is in e->counter
2598
*/
2599
        thrbufsiz2 = thrbufsiz = AC.ThreadBucketSize-1;
1,904✔
2600
        if ( ( e->counter / ( numberofworkers * 5 ) ) < thrbufsiz ) {
1,904✔
2601
                thrbufsiz = e->counter / ( numberofworkers * 5 ) - 1;
1,885✔
2602
                if ( thrbufsiz < 0 ) thrbufsiz = 0;
1,885✔
2603
        }
2604
        thrbufsiz0 = thrbufsiz;
1,904✔
2605
        numpasses = 5; /* this is just for trying */
1,904✔
2606
        thrbufsiz = thrbufsiz0 / (2 << numpasses);
1,904✔
2607
/*
2608
        Mark all buckets as free and take the first.
2609
*/
2610
        for ( j = 0; j < numthreadbuckets; j++ )
13,328✔
2611
                threadbuckets[j]->free = BUCKETFREE;
11,424✔
2612
        thr = threadbuckets[0];
1,904✔
2613
/*
2614
          #[ Whole brackets :
2615

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

2748
                        numpasses = 0;
2749
                        thrbufsiz = thrbufsiz0;
2750
*/
2751
                        AN0.lastinindex = -1;
3✔
2752
                }
2753
                MasterWaitAll();
22✔
2754
        }
2755
#endif
2756
/*
2757
          #] Whole brackets : 
2758

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

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

2927
                        All threads are busy. Try to load up another bucket.
2928
                        In the future we could be more sophisticated.
2929
                        At the moment we load a complete bucket which could be
2930
                        1000 terms or even more.
2931
                        In principle it is better to keep a full bucket ready
2932
                        and check after each term we put in the next bucket. That
2933
                        way we don't waste time of the workers.
2934
*/
2935
                        for ( j = 0; j < numthreadbuckets; j++ ) {
17,416✔
2936
                                switch ( threadbuckets[j]->free ) {
15,809✔
2937
                                        case BUCKETFREE:
2938
                                                thr = threadbuckets[j];
1,264✔
2939
                                                if ( !endofinput ) goto NextBucket;
1,264✔
2940
/*
2941
                                                If we are at the end of the input we mark
2942
                                                the free buckets in a special way. That way
2943
                                                we don't keep running into them.
2944
*/
2945
                                                thr->free = BUCKETATEND;
2946
                                                break;
2947
                                        case BUCKETCOMINGFREE:
147✔
2948
                                                thr = threadbuckets[j];
147✔
2949
                                                thr->free = BUCKETFREE;
147✔
2950
/*
2951
                                                Bucket has just been finished.
2952
                                                Put at the end of the list. We don't want
2953
                                                an early bucket to wait to be treated last.
2954
*/
2955
                                                for ( k = j+1; k < numthreadbuckets; k++ )
924✔
2956
                                                        threadbuckets[k-1] = threadbuckets[k];
777✔
2957
                                                threadbuckets[numthreadbuckets-1] = thr;
147✔
2958
                                                j--;   /* we have to redo the same number j. */
147✔
2959
                                                break;
147✔
2960
                                        default:
2961
                                                break;
2962
                                }
2963
                        }
2964
/*
2965
                        We have no free bucket or we are at the end.
2966
                        The only thing we can do now is wait for a worker to come free,
2967
                        provided there are still buckets to send.
2968
*/
2969
                }
2970
/*
2971
                Look for the next bucket to send. There is at least one full bucket!
2972
*/
2973
                for ( j = 0; j < numthreadbuckets; j++ ) {
6,678✔
2974
                        if ( threadbuckets[j]->free == BUCKETFILLED ) {
6,678✔
2975
                                thr = threadbuckets[j];
4,348✔
2976
                                for ( k = j+1; k < numthreadbuckets; k++ )
24,054✔
2977
                                        threadbuckets[k-1] = threadbuckets[k];
19,706✔
2978
                                threadbuckets[numthreadbuckets-1] = thr;
4,348✔
2979
                                break;
4,348✔
2980
                        }
2981
                }
2982
/*
2983
                Wait for a thread to become available
2984
                The bucket we are going to use is in thr.
2985
*/
2986
DoBucket:;
4,773✔
2987
                AN0.ninterms++;
5,851✔
2988
                while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
8,375✔
2989
/*
2990
                Prepare the thread. Give it the term and variables.
2991
*/
2992
                LoadOneThread(0,id,thr,0);
5,851✔
2993
                LOCK(thr->lock);
5,851✔
2994
                thr->busy = BUCKETASSIGNED;
5,851✔
2995
                UNLOCK(thr->lock);
5,851✔
2996
                thr->free = BUCKETINUSE;
5,851✔
2997
                numberoffullbuckets--;
5,851✔
2998
/*
2999
                And signal the thread to run.
3000
                Form now on we may only interfere with this bucket
3001
                1: after it has been marked BUCKETCOMINGFREE
3002
                2: when thr->busy == BUCKETDOINGTERM and then only when protected by
3003
                   thr->lock. This would be for load balancing.
3004
*/
3005
                WakeupThread(id,LOWESTLEVELGENERATION);
5,851✔
3006
/*                AN0.ninterms += thr->ddterms; */
3007
/*
3008
                Now look whether there is another bucket filled and a worker available
3009
*/
3010
                if ( topofavailables > 0 ) {  /* there is a worker */
5,851✔
3011
                        for ( j = 0; j < numthreadbuckets; j++ ) {
22,071✔
3012
                                if ( threadbuckets[j]->free == BUCKETFILLED ) {
19,537✔
3013
                                        thr = threadbuckets[j];
1,078✔
3014
                                        for ( k = j+1; k < numthreadbuckets; k++ )
4,993✔
3015
                                                threadbuckets[k-1] = threadbuckets[k];
3,915✔
3016
                                        threadbuckets[numthreadbuckets-1] = thr;
1,078✔
3017
                                        goto DoBucket; /* and we found a bucket */
1,078✔
3018
                                }
3019
                        }
3020
/*
3021
                        no bucket is loaded but there is a thread available
3022
                        find a bucket to load. If there is none (all are USED or ATEND)
3023
                        we jump out of the loop.
3024
*/
3025
                        for ( j = 0; j < numthreadbuckets; j++ ) {
3,865✔
3026
                                switch ( threadbuckets[j]->free ) {
3,770✔
3027
                                        case BUCKETFREE:
2,456✔
3028
                                                thr = threadbuckets[j];
2,456✔
3029
                                                if ( !endofinput ) goto NextBucket;
2,456✔
3030
                                                thr->free = BUCKETATEND;
17✔
3031
                                                break;
17✔
3032
                                        case BUCKETCOMINGFREE:
753✔
3033
                                                thr = threadbuckets[j];
753✔
3034
                                                if ( endofinput ) {
753✔
3035
                                                        thr->free = BUCKETATEND;
264✔
3036
                                                }
3037
                                                else {
3038
                                                        thr->free = BUCKETFREE;
489✔
3039
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
3,357✔
3040
                                                                threadbuckets[k-1] = threadbuckets[k];
2,868✔
3041
                                                        threadbuckets[numthreadbuckets-1] = thr;
489✔
3042
                                                        j--;
489✔
3043
                                                }
3044
                                                break;
3045
                                        default:
3046
                                                break;
3047
                                }
3048
                        }
3049
                        if ( j >= numthreadbuckets ) break;
95✔
3050
                }
3051
                else {
3052
/*
3053
                        No worker available.
3054
                        Look for a bucket to load.
3055
                        Its number will be in "still"
3056
*/
3057
Finalize:;
2,239✔
3058
                        still = -1;
4,194✔
3059
                        for ( j = 0; j < numthreadbuckets; j++ ) {
27,406✔
3060
                                switch ( threadbuckets[j]->free ) {
25,055✔
3061
                                        case BUCKETFREE:
10,631✔
3062
                                                thr = threadbuckets[j];
10,631✔
3063
                                                if ( !endofinput ) goto NextBucket;
10,631✔
3064
                                                thr->free = BUCKETATEND;
8,788✔
3065
                                                break;
8,788✔
3066
                                        case BUCKETCOMINGFREE:
2,772✔
3067
                                                thr = threadbuckets[j];
2,772✔
3068
                                                if ( endofinput ) thr->free = BUCKETATEND;
2,772✔
3069
                                                else {
3070
                                                        thr->free = BUCKETFREE;
2,369✔
3071
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
13,501✔
3072
                                                                threadbuckets[k-1] = threadbuckets[k];
11,132✔
3073
                                                        threadbuckets[numthreadbuckets-1] = thr;
2,369✔
3074
                                                        j--;
2,369✔
3075
                                                }
3076
                                                break;
3077
                                        case BUCKETFILLED:
3,065✔
3078
                                                if ( still < 0 ) still = j;
3,065✔
3079
                                                break;
3080
                                        default:
3081
                                                break;
3082
                                }
3083
                        }
3084
                        if ( still < 0 ) {
2,351✔
3085
/*
3086
                                No buckets to be executed and no buckets FREE.
3087
                                We must be at the end. Break out of the loop.
3088
*/
3089
                                break;
3090
                        }
3091
                        thr = threadbuckets[still];
425✔
3092
                        for ( k = still+1; k < numthreadbuckets; k++ )
2,415✔
3093
                                threadbuckets[k-1] = threadbuckets[k];
1,990✔
3094
                        threadbuckets[numthreadbuckets-1] = thr;
425✔
3095
                        goto DoBucket;
425✔
3096
                }
3097
NextBucket:;
1,904✔
3098
        }
3099
/*
3100
        Now the stage one load balancing.
3101
        If the load has been readjusted we have again filled buckets.
3102
        In that case we jump back in the loop.
3103

3104
        Tricky point: when do the workers see the new value of AT.LoadBalancing?
3105
        It should activate the locks on thr->busy
3106
*/
3107
        if ( AC.ThreadBalancing ) {
2,021✔
3108
                for ( id = 1; id <= numberofworkers; id++ ) {
8,099✔
3109
                        AB[id]->T.LoadBalancing = 1;
6,078✔
3110
                }
3111
                if ( LoadReadjusted() ) goto Finalize;
2,021✔
3112
                for ( id = 1; id <= numberofworkers; id++ ) {
7,616✔
3113
                        AB[id]->T.LoadBalancing = 0;
5,712✔
3114
                }
3115
        }
3116
        if ( AC.ThreadBalancing ) {
1,904✔
3117
/*
3118
                The AS.Balancing flag should have Generator look for
3119
                free workers and apply the "buro" method.
3120

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

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

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

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

3334
        Remember: we still have the lock to avoid interference from the thread
3335
        that is being robbed. We were holding it and then jumped here with
3336
        goto intercepted.
3337
*/
3338
        numinput = thr->firstterm + thr->usenum;
88✔
3339
        nperbucket = numtogo / numfree;
88✔
3340
        extra = numtogo - nperbucket*numfree;
88✔
3341
        if ( AR0.DeferFlag ) {
88✔
3342
                t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
2✔
3343
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
7✔
3344
                t3 = t1;
2✔
3345
                if ( extra > 0 ) {
2✔
3346
                  for ( i = 0; i < extra; i++ ) {
7✔
3347
                        thrtogo = freebuckets[i];
5✔
3348
                        t2 = thrtogo->threadbuffer;
5✔
3349
                        c2 = thrtogo->compressbuffer;
5✔
3350
                        thrtogo->free = BUCKETFILLED;
5✔
3351
                        thrtogo->type = BUCKETDOINGTERMS;
5✔
3352
                        thrtogo->totnum = nperbucket+1;
5✔
3353
                        thrtogo->ddterms = 0;
5✔
3354
                        thrtogo->usenum = 0;
5✔
3355
                        thrtogo->busy = BUCKETASSIGNED;
5✔
3356
                        thrtogo->firstterm = numinput;
5✔
3357
                        numinput += nperbucket+1;
5✔
3358
                        for ( n = 0; n <= nperbucket; n++ ) {
10✔
3359
                                j = *t1; NCOPY(t2,t1,j);
109✔
3360
                                j = *c1; NCOPY(c2,c1,j);
142✔
3361
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
5✔
3362
                        }
3363
                        *t2 = *c2 = 0;
5✔
3364
                  }
3365
                }
3366
                if ( nperbucket > 0 ) {
2✔
3367
                  for ( i = extra; i < numfree; i++ ) {
×
3368
                        thrtogo = freebuckets[i];
×
3369
                        t2 = thrtogo->threadbuffer;
×
3370
                        c2 = thrtogo->compressbuffer;
×
3371
                        thrtogo->free = BUCKETFILLED;
×
3372
                        thrtogo->type = BUCKETDOINGTERMS;
×
3373
                        thrtogo->totnum = nperbucket;
×
3374
                        thrtogo->ddterms = 0;
×
3375
                        thrtogo->usenum = 0;
×
3376
                        thrtogo->busy = BUCKETASSIGNED;
×
3377
                        thrtogo->firstterm = numinput;
×
3378
                        numinput += nperbucket;
×
3379
                        for ( n = 0; n < nperbucket; n++ ) {
×
3380
                                j = *t1; NCOPY(t2,t1,j);
×
3381
                                j = *c1; NCOPY(c2,c1,j);
×
3382
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
×
3383
                        }
3384
                        *t2 = *c2 = 0;
×
3385
                  }
3386
                }
3387
        }
3388
        else {
3389
                t1 = thr->threadbuffer;
86✔
3390
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
4,537✔
3391
                t3 = t1;
86✔
3392
                if ( extra > 0 ) {
86✔
3393
                  for ( i = 0; i < extra; i++ ) {
223✔
3394
                        thrtogo = freebuckets[i];
153✔
3395
                        t2 = thrtogo->threadbuffer;
153✔
3396
                        thrtogo->free = BUCKETFILLED;
153✔
3397
                        thrtogo->type = BUCKETDOINGTERMS;
153✔
3398
                        thrtogo->totnum = nperbucket+1;
153✔
3399
                        thrtogo->ddterms = 0;
153✔
3400
                        thrtogo->usenum = 0;
153✔
3401
                        thrtogo->busy = BUCKETASSIGNED;
153✔
3402
                        thrtogo->firstterm = numinput;
153✔
3403
                        numinput += nperbucket+1;
153✔
3404
                        for ( n = 0; n <= nperbucket; n++ ) {
2,468✔
3405
                                j = *t1; NCOPY(t2,t1,j);
529,370✔
3406
                        }
3407
                        *t2 = 0;
153✔
3408
                  }
3409
                }
3410
                if ( nperbucket > 0 ) {
86✔
3411
                  for ( i = extra; i < numfree; i++ ) {
250✔
3412
                        thrtogo = freebuckets[i];
181✔
3413
                        t2 = thrtogo->threadbuffer;
181✔
3414
                        thrtogo->free = BUCKETFILLED;
181✔
3415
                        thrtogo->type = BUCKETDOINGTERMS;
181✔
3416
                        thrtogo->totnum = nperbucket;
181✔
3417
                        thrtogo->ddterms = 0;
181✔
3418
                        thrtogo->usenum = 0;
181✔
3419
                        thrtogo->busy = BUCKETASSIGNED;
181✔
3420
                        thrtogo->firstterm = numinput;
181✔
3421
                        numinput += nperbucket;
181✔
3422
                        for ( n = 0; n < nperbucket; n++ ) {
2,897✔
3423
                                j = *t1; NCOPY(t2,t1,j);
559,447✔
3424
                        }
3425
                        *t2 = 0;
181✔
3426
                  }
3427
                }
3428
        }
3429
        *t3 = 0;   /* This is some form of extra insurance */
88✔
3430
        if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
88✔
3431
                thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
×
3432
        }
3433
        UNLOCK(thr->lock);
88✔
3434
        return(1);
88✔
3435
}
3436

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

3499
int PutToMaster(PHEAD WORD *term)
7,007,319✔
3500
{
3501
        int i,j,nexti,ret = 0;
7,007,319✔
3502
        WORD *t, *fill, *top, zero = 0;
7,007,319✔
3503
        if ( term == 0 ) { /* Mark the end of the expression */
7,007,319✔
3504
                t = &zero; j = 1;
3505
        }
3506
        else {
3507
                t = term; ret = j = *term;
6,999,863✔
3508
                if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
6,999,863✔
3509
        }
3510
        i = AT.SB.FillBlock;          /* The block we are working at */
7,007,319✔
3511
        fill = AT.SB.MasterFill[i];     /* Where we are filling */
7,007,319✔
3512
        top = AT.SB.MasterStop[i];      /* End of the block */
7,007,319✔
3513
        while ( j > 0 ) {
14,014,643✔
3514
                while ( j > 0 && fill < top ) {
186,970,631✔
3515
                        *fill++ = *t++; j--;
179,963,307✔
3516
                }
3517
                if ( j > 0 ) {
7,007,324✔
3518
/*
3519
                        We reached the end of the block.
3520
                        Get the next block and release this block.
3521
                        The order is important. This is why there should be at least
3522
                        4 blocks or deadlocks can occur.
3523
*/
3524
                        nexti = i+1;
5✔
3525
                        if ( nexti > AT.SB.MasterNumBlocks ) {
5✔
3526
                                nexti = 1;
×
3527
                        }
3528
                        LOCK(AT.SB.MasterBlockLock[nexti]);
5✔
3529
                        UNLOCK(AT.SB.MasterBlockLock[i]);
5✔
3530
                        AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
5✔
3531
                        AT.SB.FillBlock = i = nexti;
5✔
3532
                        fill = AT.SB.MasterStart[i];
5✔
3533
                        top = AT.SB.MasterStop[i];
5✔
3534
                }
3535
        }
3536
        AT.SB.MasterFill[i] = fill;
7,007,319✔
3537
        return(ret);
7,007,319✔
3538
}
3539

3540
/*
3541
          #] PutToMaster : 
3542
          #[ SortBotOut :
3543
*/
3544
 
3545
#ifdef WITHSORTBOTS
3546

3547
/**
3548
 *                This is the output routine of the SortBots.
3549
 *                It can run PutToMaster, except for the final merge.
3550
 *                In that case we need to do special things like calling PutOut.
3551
 *                Hence the first thing we have to do is to figure out where our
3552
 *                output should be going.
3553
 */
3554

3555
int
3556
SortBotOut(PHEAD WORD *term)
4,610,006✔
3557
{
3558
        WORD im;
4,610,006✔
3559

3560
        if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
4,610,006✔
3561

3562
        if ( term == 0 ) {
2,285,748✔
3563
                if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
932✔
3564
                ADDPOS(AT.SS->SizeInFile[0],1);
932✔
3565
                return(0);
932✔
3566
        }
3567
        else {
3568
                numberofterms++;
2,284,816✔
3569
                if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
2,284,816✔
3570
                        MLOCK(ErrorMessageLock);
×
3571
                        MesPrint("Called from MasterMerge/SortBotOut");
×
3572
                        MUNLOCK(ErrorMessageLock);
×
3573
                        return(-1);
×
3574
                }
3575
                ADDPOS(AT.SS->SizeInFile[0],im);
2,284,816✔
3576
                return(im);
2,284,816✔
3577
        }
3578
}
3579

3580
#endif
3581

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

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

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

3728
        start the sort
3729
*/
3730
        level = S->lPatch;
932✔
3731
/*
3732
        introduce one term
3733
*/
3734
OneTerm:
2,329,535✔
3735
        k = S->used[level];
2,330,467✔
3736
        i = k + lpat - 1;
2,330,467✔
3737
        if ( !*(poin[k]) ) {
2,330,467✔
3738
                do { if ( !( i >>= 1 ) ) goto EndOfMerge; } while ( !S->tree[i] );
2,796✔
3739
                if ( S->tree[i] == -1 ) {
932✔
3740
                        S->tree[i] = 0;
755✔
3741
                        level--;
755✔
3742
                        goto OneTerm;
755✔
3743
                }
3744
                k = S->tree[i];
177✔
3745
                S->used[level] = k;
177✔
3746
                S->tree[i] = 0;
177✔
3747
        }
3748
/*
3749
        move terms down the tree
3750
*/
3751
        while ( i >>= 1 ) {
4,613,419✔
3752
                if ( S->tree[i] > 0 ) {
2,328,603✔
3753
                        if ( ( c = CompareTerms(B0, poin[S->tree[i]],poin[k],(WORD)0) ) > 0 ) {
42,692✔
3754
/*
3755
                                S->tree[i] is the smaller. Exchange and go on.
3756
*/
3757
                                S->used[level] = S->tree[i];
2,097✔
3758
                                S->tree[i] = k;
2,097✔
3759
                                k = S->used[level];
2,097✔
3760
                        }
3761
                        else if ( !c ) {        /* Terms are equal */
40,595✔
3762
/*
3763
                                S->TermsLeft--;
3764
                                        Here the terms are equal and their coefficients
3765
                                        have to be added.
3766
*/
3767
                                l1 = *( m1 = poin[S->tree[i]] );
22,395✔
3768
                                l2 = *( m2 = poin[k] );
22,395✔
3769
                                if ( S->PolyWise ) {  /* Here we work with PolyFun */
22,395✔
3770
                                        WORD *tt1, *w;
922✔
3771
                                        tt1 = m1;
922✔
3772
                                        m1 += S->PolyWise;
922✔
3773
                                        m2 += S->PolyWise;
922✔
3774
                                        if ( S->PolyFlag == 2 ) {
922✔
3775
                                                w = poly_ratfun_add(B0,m1,m2);
921✔
3776
                                                if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
921✔
3777
                                                        MLOCK(ErrorMessageLock);
×
3778
                                                        MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
3779
                                                        MUNLOCK(ErrorMessageLock);
×
3780
                                                        Terminate(-1);
×
3781
                                                }
3782
                                                AT0.WorkPointer = w;
921✔
3783
                                                if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
921✔
3784
                                                        goto cancelled;
795✔
3785
                                                }
3786
                                        }
3787
                                        else {
3788
                                                w = AT0.WorkPointer;
1✔
3789
                                                if ( w + m1[1] + m2[1] > AT0.WorkTop ) {
1✔
3790
                                                        MLOCK(ErrorMessageLock);
×
3791
                                                        MesPrint("MasterMerge: A WorkSpace of %10l is too small",AM.WorkSize);
×
3792
                                                        MUNLOCK(ErrorMessageLock);
×
3793
                                                        Terminate(-1);
×
3794
                                                }
3795
                                                AddArgs(B0,m1,m2,w);
1✔
3796
                                        }
3797
                                        r1 = w[1];
127✔
3798
                                        if ( r1 <= FUNHEAD
127✔
3799
                                                || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
127✔
3800
                                                         { goto cancelled; }
×
3801
                                        if ( r1 == m1[1] ) {
127✔
3802
                                                NCOPY(m1,w,r1);
50✔
3803
                                        }
3804
                                        else if ( r1 < m1[1] ) {
125✔
3805
                                                r2 = m1[1] - r1;
9✔
3806
                                                m2 = w + r1;
9✔
3807
                                                m1 += m1[1];
9✔
3808
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
84,522✔
3809
                                                m2 = m1 - r2;
9✔
3810
                                                r1 = S->PolyWise;
9✔
3811
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
120✔
3812
                                                *m1 -= r2;
9✔
3813
                                                poin[S->tree[i]] = m1;
9✔
3814
                                        }
3815
                                        else {
3816
                                                r2 = r1 - m1[1];
116✔
3817
                                                m2 = tt1 - r2;
116✔
3818
                                                r1 = S->PolyWise;
116✔
3819
                                                m1 = tt1;
116✔
3820
                                                *m1 += r2;
116✔
3821
                                                poin[S->tree[i]] = m2;
116✔
3822
                                                NCOPY(m2,m1,r1);
862✔
3823
                                                r1 = w[1];
116✔
3824
                                                NCOPY(m2,w,r1);
1,351,192✔
3825
                                        }
3826
                                }
3827
#ifdef WITHFLOAT
3828
                                else if ( AT.SortFloatMode ) {
21,473✔
3829
                                        WORD *term1, *term2;
×
3830
                                        term1 = poin[S->tree[i]];
×
3831
                                        term2 = poin[k];
×
3832
                                        if ( MergeWithFloat(B0, &term1,&term2) == 0 )
×
3833
                                                goto cancelled;
×
3834
                                        poin[S->tree[i]] = term1;
×
3835
                                }
3836
#endif
3837
                                else {
3838
                                        r1 = *( m1 += l1 - 1 );
21,473✔
3839
                                        m1 -= ABS(r1) - 1;
21,473✔
3840
                                        r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
21,473✔
3841
                                        r2 = *( m2 += l2 - 1 );
21,473✔
3842
                                        m2 -= ABS(r2) - 1;
21,473✔
3843
                                        r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
21,473✔
3844

3845
                                        if ( AddRat(B0,(UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
21,473✔
3846
                                                MLOCK(ErrorMessageLock);
×
3847
                                                MesCall("MasterMerge");
×
3848
                                                MUNLOCK(ErrorMessageLock);
×
3849
                                                SETERROR(-1)
×
3850
                                        }
3851

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

4062
/*
4063
          #] MasterMerge : 
4064
          #[ SortBotMasterMerge :
4065
*/
4066
 
4067
#ifdef WITHSORTBOTS
4068

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

4084
int SortBotMasterMerge(VOID)
933✔
4085
{
4086
        FILEHANDLE *fin, *fout;
933✔
4087
        ALLPRIVATES *B = AB[0], *BB;
933✔
4088
        POSITION position;
933✔
4089
        SORTING *S = AT.SS;
933✔
4090
        int i, j;
933✔
4091
/*
4092
        Get the sortbots get to claim their writing blocks.
4093
        We have to wait till all have been claimed because they also have to
4094
        claim the last writing blocks of the workers to prevent the head of
4095
        the circular buffer to overrun the tail.
4096

4097
        Before waiting we can do some needed initializations.
4098
        Also the master has to claim the last writing blocks of its input.
4099
*/
4100
        topsortbotavailables = 0;
933✔
4101
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
2,799✔
4102
                WakeupThread(i,INISORTBOT);
1,866✔
4103
        }
4104

4105
        AS.MasterSort = 1;
933✔
4106
        fout = AR.outfile;
933✔
4107
        numberofterms = 0;
933✔
4108
        AR.CompressPointer[0] = 0;
933✔
4109
        numberclaimed = 0;
933✔
4110
        BB = AB[AT.SortBotIn1];
933✔
4111
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
933✔
4112
        BB = AB[AT.SortBotIn2];
933✔
4113
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
933✔
4114

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

4182
        return(0);
932✔
4183
}
4184

4185
#endif
4186

4187
/*
4188
          #] SortBotMasterMerge : 
4189
          #[ SortBotMerge :
4190
*/
4191
 
4192
#ifdef WITHSORTBOTS
4193

4194
/**
4195
 *        This routine is run by a sortbot and merges two sorted output streams into
4196
 *        a single sorted stream.
4197
 */
4198

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

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

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

4490
                                if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
32,296✔
4491
                                        MLOCK(ErrorMessageLock);
×
4492
                                        MesCall("SortBotMerge");
×
4493
                                        MUNLOCK(ErrorMessageLock);
×
4494
                                        SETERROR(-1)
×
4495
                                }
4496

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

4697
#endif
4698

4699
/*
4700
          #] SortBotMerge : 
4701
          #[ IniSortBlocks :
4702
*/
4703
 
4704
static int SortBlocksInitialized = 0;
4705

4706
/**
4707
 *        Initializes the blocks in the sort buffers of the master.
4708
 *        These blocks are needed to keep both the workers and the master working
4709
 *        simultaneously. See also the commentary at the routine MasterMerge.
4710
 */
4711

4712
int IniSortBlocks(int numworkers)
588✔
4713
{
4714
        ALLPRIVATES *B;
588✔
4715
        SORTING *S;
588✔
4716
        LONG totalsize, workersize, blocksize, numberofterms;
588✔
4717
        int maxter, id, j;
588✔
4718
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
588✔
4719
        WORD *w;
588✔
4720

4721
        if ( SortBlocksInitialized ) return(0);
588✔
4722
        SortBlocksInitialized = 1;
588✔
4723
        if ( numworkers == 0 ) return(0);
588✔
4724

4725
#ifdef WITHSORTBOTS
4726
        if ( numworkers > 2 ) {
584✔
4727
                numparts = 2*numworkers - 2;
292✔
4728
                numberofblocks = numberofblocks/2;
292✔
4729
        }
4730
        else {
4731
                numparts = numworkers;
4732
        }
4733
#else
4734
        numparts = numworkers;
4735
#endif
4736
        S = AM.S0;
584✔
4737
        totalsize = S->LargeSize + S->SmallEsize;
584✔
4738
        workersize = totalsize / numparts;
584✔
4739
        maxter = AM.MaxTer/sizeof(WORD);
584✔
4740
        blocksize = ( workersize - maxter )/numberofblocks;
584✔
4741
        numberofterms = blocksize / maxter;
584✔
4742
        if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
584✔
4743
/*
4744
                This should have been taken care of in RecalcSetups.
4745
*/
4746
                MesPrint("We have a problem with the size of the blocks in IniSortBlocks");
×
4747
                Terminate(-1);
×
4748
        }
4749
/*
4750
        Layout:  For each worker
4751
                                block 0: size is maxter WORDS
4752
                                numberofblocks blocks of size blocksize WORDS
4753
*/
4754
        w = S->lBuffer;
584✔
4755
        if ( w == 0 ) w = S->sBuffer;
584✔
4756
        for ( id = 1; id <= numparts; id++ ) {
2,920✔
4757
                B = AB[id];
2,336✔
4758
                AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
4,672✔
4759
                        sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
2,336✔
4760
                AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
2,336✔
4761
                AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
2,336✔
4762
                AT.SB.MasterStop = AT.SB.MasterFill  + (numberofblocks+1);
2,336✔
4763
                AT.SB.MasterNumBlocks = numberofblocks;
2,336✔
4764
                AT.SB.MasterBlock = 0;
2,336✔
4765
                AT.SB.FillBlock = 0;
2,336✔
4766
                AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
2,336✔
4767
                w += maxter;
2,336✔
4768
                AT.SB.MasterStop[0] = w;
2,336✔
4769
                AT.SB.MasterBlockLock[0] = dummylock;
2,336✔
4770
                for ( j = 1; j <= numberofblocks; j++ ) {
16,936✔
4771
                        AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
14,600✔
4772
                        w += blocksize;
14,600✔
4773
                        AT.SB.MasterStop[j] = w;
14,600✔
4774
                        AT.SB.MasterBlockLock[j] = dummylock;
14,600✔
4775
                }
4776
        }
4777
        if ( w > S->sTop2 ) {
584✔
4778
                MesPrint("Counting problem in IniSortBlocks");
×
4779
                Terminate(-1);
×
4780
        }
4781
        return(0);
4782
}
4783

4784
/*
4785
          #] IniSortBlocks : 
4786
          #[ UpdateSortBlocks :
4787
*/
4788
 
4789
/**
4790
 *        A version of IniSortBlocks which only updates the pointers in the master's
4791
 *        buffer, to be used after reallocation of that buffer.
4792
 */
4793
int UpdateSortBlocks(int numworkers)
8✔
4794
{
4795
        ALLPRIVATES *B;
8✔
4796
        SORTING *S;
8✔
4797
        LONG totalsize, workersize, blocksize, numberofterms;
8✔
4798
        int maxter, id, j;
8✔
4799
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
8✔
4800
        WORD *w;
8✔
4801

4802
        if ( numworkers == 0 ) return(0);
8✔
4803

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

4853
/*
4854
          #] UpdateSortBlocks : 
4855
          #[ DefineSortBotTree :
4856
*/
4857
 
4858
#ifdef WITHSORTBOTS
4859

4860
/**
4861
 *        To be used in a sortbot merge. It initializes the whole sortbot
4862
 *        system by telling the sortbot which threads provide their input.
4863
 */
4864

4865
void DefineSortBotTree(VOID)
588✔
4866
{
4867
        ALLPRIVATES *B;
588✔
4868
        int n, i, from;
588✔
4869
        if ( numberofworkers <= 2 ) return;
588✔
4870
        n = numberofworkers*2-2;
292✔
4871
        for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
876✔
4872
                B = AB[i];
584✔
4873
                AT.SortBotIn1 = from++;
584✔
4874
                AT.SortBotIn2 = from++;
584✔
4875
        }
4876
        B = AB[0];
292✔
4877
        AT.SortBotIn1 = from++;
292✔
4878
        AT.SortBotIn2 = from++;
292✔
4879
}
4880

4881
#endif
4882

4883
/*
4884
          #] DefineSortBotTree : 
4885
          #[ GetTerm2 :
4886

4887
        Routine does a GetTerm but only when a bracket index is involved and
4888
        only from brackets that have been judged not suitable for treatment
4889
        as complete brackets by a single worker. Whether or not a bracket should
4890
        be treated by a single worker is decided by TreatIndexEntry
4891
*/
4892

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

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

5032
/*
5033
          #] TreatIndexEntry : 
5034
          #[ SetHideFiles :
5035
*/
5036

5037
void SetHideFiles(VOID) {
30✔
5038
        int i;
30✔
5039
        ALLPRIVATES *B, *B0 = AB[0];
30✔
5040
        for ( i = 1; i <= numberofworkers; i++ ) {
120✔
5041
                B = AB[i];
90✔
5042
                AR.hidefile->handle = AR0.hidefile->handle;
90✔
5043
                if ( AR.hidefile->handle < 0 ) {
90✔
5044
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
90✔
5045
                        AR.hidefile->POstop = AR0.hidefile->POstop;
90✔
5046
                        AR.hidefile->POfill = AR0.hidefile->POfill;
90✔
5047
                        AR.hidefile->POfull = AR0.hidefile->POfull;
90✔
5048
                        AR.hidefile->POsize = AR0.hidefile->POsize;
90✔
5049
                        AR.hidefile->POposition = AR0.hidefile->POposition;
90✔
5050
                        AR.hidefile->filesize = AR0.hidefile->filesize;
90✔
5051
                }
5052
                else {
5053
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
5054
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
5055
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
5056
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
5057
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
5058
                        PUTZERO(AR.hidefile->POposition);
×
5059
                }
5060
        }
5061
}
30✔
5062

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

5068
void IniFbufs(VOID)
588✔
5069
{
5070
        int i;
588✔
5071
        for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
2,928✔
5072
                IniFbuffer(AB[i]->T.fbufnum);
2,340✔
5073
        }
5074
}
588✔
5075

5076
/*
5077
          #] IniFbufs : 
5078
          #[ SetMods :
5079
*/
5080

5081
void SetMods(VOID)
2✔
5082
{
5083
        ALLPRIVATES *B;
2✔
5084
        int i, n, j;
2✔
5085
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
10✔
5086
                B = AB[j];
8✔
5087
                AN.ncmod = AC.ncmod;
8✔
5088
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
8✔
5089
                n = ABS(AN.ncmod);
8✔
5090
                AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
8✔
5091
                for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
16✔
5092
        }
5093
}
2✔
5094

5095
/*
5096
          #] SetMods : 
5097
          #[ UnSetMods :
5098
*/
5099

5100
void UnSetMods(VOID)
2✔
5101
{
5102
        ALLPRIVATES *B;
2✔
5103
        int j;
2✔
5104
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
10✔
5105
                B = AB[j];
8✔
5106
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
8✔
5107
                AN.cmod = 0;
8✔
5108
        }
5109
}
2✔
5110

5111
/*
5112
          #] UnSetMods : 
5113
          #[ find_Horner_MCTS_expand_tree_threaded :
5114
*/
5115
 
5116
void find_Horner_MCTS_expand_tree_threaded(VOID) {
61✔
5117
        int id;
61✔
5118
        while (( id = GetAvailableThread() ) < 0)
91✔
5119
                MasterWait();        
30✔
5120
        WakeupThread(id,MCTSEXPANDTREE);
61✔
5121
}
61✔
5122

5123
/*
5124
          #] find_Horner_MCTS_expand_tree_threaded : 
5125
          #[ optimize_expression_given_Horner_threaded :
5126
*/
5127
 
5128
extern void optimize_expression_given_Horner_threaded(VOID) {
30✔
5129
        int id;
30✔
5130
        while (( id = GetAvailableThread() ) < 0)
30✔
5131
                MasterWait();        
×
5132
        WakeupThread(id,OPTIMIZEEXPRESSION);
30✔
5133
}
30✔
5134

5135
/*
5136
          #] optimize_expression_given_Horner_threaded : 
5137
*/
5138

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

© 2026 Coveralls, Inc