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

vermaseren / form / 9168328052

21 May 2024 03:22AM UTC coverage: 48.973% (+0.2%) from 48.764%
9168328052

Pull #522

github

web-flow
Merge f292331f5 into 87b4bcf29
Pull Request #522: ci: add test jobs for tform/tvorm -w2

40542 of 82784 relevant lines covered (48.97%)

821390.67 hits per line

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

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

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

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

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

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

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

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

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

397
        bsize = sizeof(ALLPRIVATES);
2,522✔
398
        bsize = (bsize+sizeof(int)-1)/sizeof(int);
2,522✔
399
        B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
2,522✔
400
        for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
15,015,980✔
401

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

421
#ifdef WITHSORTBOTS
422

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

831
VOID TerminateAllThreads(VOID)
466✔
832
{
833
        int i;
466✔
834
        for ( i = 1; i <= numberofworkers; i++ ) {
1,858✔
835
                GetThread(i);
1,392✔
836
                WakeupThread(i,TERMINATETHREAD);
1,392✔
837
        }
838
#ifdef WITHSORTBOTS
839
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
930✔
840
                WakeupThread(i,TERMINATETHREAD);
464✔
841
        }
842
#endif
843
        for ( i = 1; i <= numberofworkers; i++ ) {
1,858✔
844
                pthread_join(threadpointers[i],NULL);
1,392✔
845
        }
846
#ifdef WITHSORTBOTS
847
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
930✔
848
                pthread_join(threadpointers[i],NULL);
464✔
849
        }
850
#endif
851
}
466✔
852

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

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

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

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

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

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

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

985
LONG GetWorkerTimes(VOID)
1,008✔
986
{
987
        LONG retval = 0;
1,008✔
988
        int i;
1,008✔
989
        for ( i = 1; i <= numberofworkers; i++ ) retval += timerinfo[i] + sumtimerinfo[i];
4,026✔
990
#ifdef WITHSORTBOTS
991
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ )
2,014✔
992
                retval += timerinfo[i] + sumtimerinfo[i];
1,006✔
993
#endif
994
        return(retval);
1,008✔
995
}
996

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

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

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

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

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

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

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

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

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

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

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

1162
        WakeupThread(identity,HIGHERLEVELGENERATION);
×
1163

1164
        return(0);
×
1165
}
1166

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

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

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

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

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

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

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

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

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

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

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

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

1771
                                AT.WorkPointer = oldwork;
2✔
1772

1773
                                } break;
2✔
1774
/*
1775
                        #] DOONEEXPRESSION : 
1776
                        #[ DOBRACKETS :
1777

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

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

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

1917
#ifdef WITHSORTBOTS
1918

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

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

2006
#endif
2007

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

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

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

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

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

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

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

2115
int GetThread(int identity)
11,268✔
2116
{
2117
        int retval = -1, j;
11,268✔
2118
        LOCK(availabilitylock);
11,268✔
2119
        for ( j = 0; j < topofavailables; j++ ) {
31,546✔
2120
                if ( identity == listofavailables[j] ) break;
20,278✔
2121
        }
2122
        if ( j < topofavailables ) {
11,268✔
2123
                --topofavailables;
11,268✔
2124
                for ( ; j < topofavailables; j++ ) {
16,095✔
2125
                        listofavailables[j] = listofavailables[j+1];
4,827✔
2126
                }
2127
                retval = identity;
2128
        }
2129
        UNLOCK(availabilitylock);
11,268✔
2130
        return(retval);
11,268✔
2131
}
2132

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

2146
int ThreadWait(int identity)
20,731✔
2147
{
2148
        int retval, top, j;
20,731✔
2149
        LOCK(wakeuplocks[identity]);
20,731✔
2150
        LOCK(availabilitylock);
20,731✔
2151
        top = topofavailables;
20,731✔
2152
        for ( j = topofavailables; j > 0; j-- )
45,114✔
2153
                listofavailables[j] = listofavailables[j-1];
24,383✔
2154
        listofavailables[0] = identity;
20,731✔
2155
        topofavailables++;
20,731✔
2156
        if ( top == 0 || topofavailables == numberofworkers ) {
20,731✔
2157
                UNLOCK(availabilitylock);
13,980✔
2158
                LOCK(wakeupmasterlock);
13,980✔
2159
                wakeupmaster = identity;
13,980✔
2160
                pthread_cond_signal(&wakeupmasterconditions);
13,980✔
2161
                UNLOCK(wakeupmasterlock);
13,980✔
2162
        }
2163
        else {
2164
                UNLOCK(availabilitylock);
6,751✔
2165
        }
2166
        while ( wakeup[identity] == 0 ) {
41,362✔
2167
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
20,731✔
2168
        }
2169
        retval = wakeup[identity];
20,631✔
2170
        wakeup[identity] = 0;
20,631✔
2171
        UNLOCK(wakeuplocks[identity]);
20,631✔
2172
        return(retval);
20,631✔
2173
}
2174

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

2190
int SortBotWait(int identity)
3,796✔
2191
{
2192
        int retval;
3,796✔
2193
        LOCK(wakeuplocks[identity]);
3,796✔
2194
        LOCK(availabilitylock);
3,796✔
2195
        topsortbotavailables++;
3,796✔
2196
        if ( topsortbotavailables >= numberofsortbots ) {
3,796✔
2197
                UNLOCK(availabilitylock);
1,898✔
2198
                LOCK(wakeupsortbotlock);
1,898✔
2199
                wakeupmaster = identity;
1,898✔
2200
                pthread_cond_signal(&wakeupsortbotconditions);
1,898✔
2201
                UNLOCK(wakeupsortbotlock);
1,898✔
2202
        }
2203
        else {
2204
                UNLOCK(availabilitylock);
1,898✔
2205
        }
2206
        while ( wakeup[identity] == 0 ) {
7,552✔
2207
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
3,796✔
2208
        }
2209
        retval = wakeup[identity];
3,756✔
2210
        wakeup[identity] = 0;
3,756✔
2211
        UNLOCK(wakeuplocks[identity]);
3,756✔
2212
        return(retval);
3,756✔
2213
}
2214

2215
#endif
2216

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

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

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

2259
int MasterWait(VOID)
1,773✔
2260
{
2261
        int retval;
1,773✔
2262
        LOCK(wakeupmasterlock);
1,773✔
2263
        while ( wakeupmaster == 0 ) {
3,130✔
2264
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
1,357✔
2265
        }
2266
        retval = wakeupmaster;
1,773✔
2267
        wakeupmaster = 0;
1,773✔
2268
        UNLOCK(wakeupmasterlock);
1,773✔
2269
        return(retval);
1,773✔
2270
}
2271

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

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

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

2306
void MasterWaitAll(VOID)
7,178✔
2307
{
2308
        LOCK(wakeupmasterlock);
7,178✔
2309
        while ( topofavailables < numberofworkers ) {
13,302✔
2310
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
6,144✔
2311
        }
2312
        UNLOCK(wakeupmasterlock);
7,158✔
2313
        return;
7,158✔
2314
}
2315

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

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

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

2338
#endif
2339

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

2350
void MasterWaitAllBlocks(VOID)
1,646✔
2351
{
2352
        LOCK(wakeupmasterlock);
1,646✔
2353
        while ( numberclaimed < numberofworkers ) {
3,415✔
2354
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
1,769✔
2355
        }
2356
        UNLOCK(wakeupmasterlock);
1,646✔
2357
        return;
1,646✔
2358
}
2359

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3103
        Tricky point: when do the workers see the new value of AT.LoadBalancing?
3104
        It should activate the locks on thr->busy
3105
*/
3106
        if ( AC.ThreadBalancing ) {
24,070✔
3107
                for ( id = 1; id <= numberofworkers; id++ ) {
116,376✔
3108
                        AB[id]->T.LoadBalancing = 1;
92,306✔
3109
                }
3110
                if ( LoadReadjusted() ) goto Finalize;
24,070✔
3111
                for ( id = 1; id <= numberofworkers; id++ ) {
6,664✔
3112
                        AB[id]->T.LoadBalancing = 0;
4,998✔
3113
                }
3114
        }
3115
        if ( AC.ThreadBalancing ) {
1,666✔
3116
/*
3117
                The AS.Balancing flag should have Generator look for
3118
                free workers and apply the "buro" method.
3119

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

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

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

3217
int LoadReadjusted(VOID)
24,070✔
3218
{
3219
        ALLPRIVATES *B0 = AB[0];
24,070✔
3220
        THREADBUCKET *thr = 0, *thrtogo = 0;
24,070✔
3221
        int numtogo, numfree, numbusy, n, nperbucket, extra, i, j, u, bus;
24,070✔
3222
        LONG numinput;
24,070✔
3223
        WORD *t1, *c1, *t2, *c2, *t3;
24,070✔
3224
/*
3225
        Start with waiting for at least one free processor.
3226
        We don't want the master competing for time when all are busy.
3227
*/
3228
        while ( topofavailables <= 0 ) MasterWait();
24,259✔
3229
/*
3230
        Now look for the fullest bucket and make a list of free buckets
3231
        The bad part is that most numbers can change at any moment.
3232
*/
3233
restart:;
25,990✔
3234
        numtogo = 0;
25,990✔
3235
        numfree = 0;
25,990✔
3236
        numbusy = 0;
25,990✔
3237
        for ( j = 0; j < numthreadbuckets; j++ ) {
225,962✔
3238
                thr = threadbuckets[j];
199,972✔
3239
                if ( thr->free == BUCKETFREE || thr->free == BUCKETATEND
199,972✔
3240
                || thr->free == BUCKETCOMINGFREE ) {
32,325✔
3241
                        freebuckets[numfree++] = thr;
173,061✔
3242
                }
3243
                else if ( thr->type != BUCKETDOINGTERMS ) {}
26,911✔
3244
                else if ( thr->totnum > 1 ) { /* never steal from a bucket with one term */
26,911✔
3245
                        LOCK(thr->lock);
25,117✔
3246
                        bus = thr->busy;
25,117✔
3247
                        UNLOCK(thr->lock);
25,117✔
3248
                        if ( thr->free == BUCKETINUSE ) {
25,117✔
3249
                                n = thr->totnum-thr->usenum;
25,026✔
3250
                                if ( bus == BUCKETASSIGNED ) numbusy++;
25,026✔
3251
                                else if ( ( bus != BUCKETASSIGNED )
2,604✔
3252
                                           && ( n > numtogo ) ) {
2,604✔
3253
                                        numtogo = n;
2,216✔
3254
                                        thrtogo = thr;
2,216✔
3255
                                }
3256
                        }
3257
                        else if ( bus == BUCKETTOBERELEASED
91✔
3258
                         && thr->free == BUCKETRELEASED ) {
85✔
3259
                                freebuckets[numfree++] = thr;
84✔
3260
                                thr->free = BUCKETATEND;
84✔
3261
                                LOCK(thr->lock);
84✔
3262
                                thr->busy = BUCKETPREPARINGTERM;
84✔
3263
                                UNLOCK(thr->lock);
84✔
3264
                        }
3265
                }
3266
        }
3267
        if ( numfree == 0 ) return(0); /* serious problem */
25,990✔
3268
        if ( numtogo > 0 ) {   /* provisionally there is something to be stolen */
25,990✔
3269
                thr = thrtogo;
2,008✔
3270
/*
3271
                If the number has changed there is good progress.
3272
                Maybe there is another thread that needs assistance.
3273
                We start all over.
3274
*/
3275
                if ( thr->totnum-thr->usenum < numtogo ) goto restart;
2,008✔
3276
/*
3277
                If the thread is in the term loading phase
3278
                (thr->busy == BUCKETPREPARINGTERM) we better stay away from it.
3279
                We wait now for the thread to be busy, and don't allow it
3280
                now to drop out of this state till we are done here.
3281
                This all depends on whether AT.LoadBalancing == 1 is seen by
3282
                the thread.
3283
*/
3284
                LOCK(thr->lock);
2,007✔
3285
                if ( thr->busy != BUCKETDOINGTERM ) {
2,007✔
3286
                        UNLOCK(thr->lock);
1,919✔
3287
                        goto restart;
1,919✔
3288
                }
3289
                if ( thr->totnum-thr->usenum < numtogo ) {
88✔
3290
                        UNLOCK(thr->lock);
×
3291
                        goto restart;
×
3292
                }
3293
                thr->free = BUCKETTERMINATED;
88✔
3294
/*
3295
                The above will signal the thread we want to terminate.
3296
                Next all effort goes into making sure the landing is soft.
3297
                Unfortunately we don't want to wait for a signal, because the thread
3298
                may be working for a long time on a single term.
3299
*/
3300
                if ( thr->usenum == thr->totnum ) {
88✔
3301
/*
3302
                        Terminated in the mean time or by now working on the
3303
                        last term. Try again.
3304
*/
3305
                        thr->free = BUCKETATEND;
×
3306
                        UNLOCK(thr->lock);
×
3307
                        goto restart;
×
3308
                }
3309
                goto intercepted;
88✔
3310
        }
3311
/*        UNLOCK(thr->lock); */
3312
        if ( numbusy > 0 ) return(1); /* Wait a bit.... */
23,982✔
3313
        return(0);
3314
intercepted:;
88✔
3315
/*
3316
        We intercepted one successfully. Now it becomes interesting. Action:
3317
        1: determine how many terms per free bucket.
3318
        2: find the first untreated term.
3319
        3: put the terms in the free buckets.
3320

3321
        Remember: we have the lock to avoid interference from the thread
3322
        that is being robbed.
3323
*/
3324
        numinput = thr->firstterm + thr->usenum;
88✔
3325
        nperbucket = numtogo / numfree;
88✔
3326
        extra = numtogo - nperbucket*numfree;
88✔
3327
        if ( AR0.DeferFlag ) {
88✔
3328
                t1 = thr->threadbuffer; c1 = thr->compressbuffer; u = thr->usenum;
×
3329
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; c1 += *c1; }
×
3330
                t3 = t1;
×
3331
                if ( extra > 0 ) {
×
3332
                  for ( i = 0; i < extra; i++ ) {
×
3333
                        thrtogo = freebuckets[i];
×
3334
                        t2 = thrtogo->threadbuffer;
×
3335
                        c2 = thrtogo->compressbuffer;
×
3336
                        thrtogo->free = BUCKETFILLED;
×
3337
                        thrtogo->type = BUCKETDOINGTERMS;
×
3338
                        thrtogo->totnum = nperbucket+1;
×
3339
                        thrtogo->ddterms = 0;
×
3340
                        thrtogo->usenum = 0;
×
3341
                        thrtogo->busy = BUCKETASSIGNED;
×
3342
                        thrtogo->firstterm = numinput;
×
3343
                        numinput += nperbucket+1;
×
3344
                        for ( n = 0; n <= nperbucket; n++ ) {
×
3345
                                j = *t1; NCOPY(t2,t1,j);
×
3346
                                j = *c1; NCOPY(c2,c1,j);
×
3347
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
×
3348
                        }
3349
                        *t2 = *c2 = 0;
×
3350
                  }
3351
                }
3352
                if ( nperbucket > 0 ) {
×
3353
                  for ( i = extra; i < numfree; i++ ) {
×
3354
                        thrtogo = freebuckets[i];
×
3355
                        t2 = thrtogo->threadbuffer;
×
3356
                        c2 = thrtogo->compressbuffer;
×
3357
                        thrtogo->free = BUCKETFILLED;
×
3358
                        thrtogo->type = BUCKETDOINGTERMS;
×
3359
                        thrtogo->totnum = nperbucket;
×
3360
                        thrtogo->ddterms = 0;
×
3361
                        thrtogo->usenum = 0;
×
3362
                        thrtogo->busy = BUCKETASSIGNED;
×
3363
                        thrtogo->firstterm = numinput;
×
3364
                        numinput += nperbucket;
×
3365
                        for ( n = 0; n < nperbucket; n++ ) {
×
3366
                                j = *t1; NCOPY(t2,t1,j);
×
3367
                                j = *c1; NCOPY(c2,c1,j);
×
3368
                                thrtogo->deferbuffer[n] = thr->deferbuffer[u++];
×
3369
                        }
3370
                        *t2 = *c2 = 0;
×
3371
                  }
3372
                }
3373
        }
3374
        else {
3375
                t1 = thr->threadbuffer;
88✔
3376
                for ( n = 0; n < thr->usenum; n++ ) { t1 += *t1; }
2,036✔
3377
                t3 = t1;
88✔
3378
                if ( extra > 0 ) {
88✔
3379
                  for ( i = 0; i < extra; i++ ) {
213✔
3380
                        thrtogo = freebuckets[i];
145✔
3381
                        t2 = thrtogo->threadbuffer;
145✔
3382
                        thrtogo->free = BUCKETFILLED;
145✔
3383
                        thrtogo->type = BUCKETDOINGTERMS;
145✔
3384
                        thrtogo->totnum = nperbucket+1;
145✔
3385
                        thrtogo->ddterms = 0;
145✔
3386
                        thrtogo->usenum = 0;
145✔
3387
                        thrtogo->busy = BUCKETASSIGNED;
145✔
3388
                        thrtogo->firstterm = numinput;
145✔
3389
                        numinput += nperbucket+1;
145✔
3390
                        for ( n = 0; n <= nperbucket; n++ ) {
1,668✔
3391
                                j = *t1; NCOPY(t2,t1,j);
254,343✔
3392
                        }
3393
                        *t2 = 0;
145✔
3394
                  }
3395
                }
3396
                if ( nperbucket > 0 ) {
88✔
3397
                  for ( i = extra; i < numfree; i++ ) {
215✔
3398
                        thrtogo = freebuckets[i];
154✔
3399
                        t2 = thrtogo->threadbuffer;
154✔
3400
                        thrtogo->free = BUCKETFILLED;
154✔
3401
                        thrtogo->type = BUCKETDOINGTERMS;
154✔
3402
                        thrtogo->totnum = nperbucket;
154✔
3403
                        thrtogo->ddterms = 0;
154✔
3404
                        thrtogo->usenum = 0;
154✔
3405
                        thrtogo->busy = BUCKETASSIGNED;
154✔
3406
                        thrtogo->firstterm = numinput;
154✔
3407
                        numinput += nperbucket;
154✔
3408
                        for ( n = 0; n < nperbucket; n++ ) {
2,755✔
3409
                                j = *t1; NCOPY(t2,t1,j);
790,724✔
3410
                        }
3411
                        *t2 = 0;
154✔
3412
                  }
3413
                }
3414
        }
3415
        *t3 = 0;   /* This is some form of extra insurance */
88✔
3416
        if ( thr->free == BUCKETRELEASED && thr->busy == BUCKETTOBERELEASED ) {
88✔
3417
                thr->free = BUCKETATEND; thr->busy = BUCKETPREPARINGTERM;
×
3418
        }
3419
        UNLOCK(thr->lock);
88✔
3420
        return(1);
88✔
3421
}
3422

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

3485
int PutToMaster(PHEAD WORD *term)
6,668,950✔
3486
{
3487
        int i,j,nexti,ret = 0;
6,668,950✔
3488
        WORD *t, *fill, *top, zero = 0;
6,668,950✔
3489
        if ( term == 0 ) { /* Mark the end of the expression */
6,668,950✔
3490
                t = &zero; j = 1;
3491
        }
3492
        else {
3493
                t = term; ret = j = *term;
6,662,360✔
3494
                if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
6,662,360✔
3495
        }
3496
        i = AT.SB.FillBlock;          /* The block we are working at */
6,668,950✔
3497
        fill = AT.SB.MasterFill[i];     /* Where we are filling */
6,668,950✔
3498
        top = AT.SB.MasterStop[i];      /* End of the block */
6,668,950✔
3499
        while ( j > 0 ) {
13,337,900✔
3500
                while ( j > 0 && fill < top ) {
164,944,600✔
3501
                        *fill++ = *t++; j--;
158,275,800✔
3502
                }
3503
                if ( j > 0 ) {
6,668,960✔
3504
/*
3505
                        We reached the end of the block.
3506
                        Get the next block and release this block.
3507
                        The order is important. This is why there should be at least
3508
                        4 blocks or deadlocks can occur.
3509
*/
3510
                        nexti = i+1;
5✔
3511
                        if ( nexti > AT.SB.MasterNumBlocks ) {
5✔
3512
                                nexti = 1;
×
3513
                        }
3514
                        LOCK(AT.SB.MasterBlockLock[nexti]);
5✔
3515
                        UNLOCK(AT.SB.MasterBlockLock[i]);
5✔
3516
                        AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
5✔
3517
                        AT.SB.FillBlock = i = nexti;
5✔
3518
                        fill = AT.SB.MasterStart[i];
5✔
3519
                        top = AT.SB.MasterStop[i];
5✔
3520
                }
3521
        }
3522
        AT.SB.MasterFill[i] = fill;
6,668,950✔
3523
        return(ret);
6,668,950✔
3524
}
3525

3526
/*
3527
          #] PutToMaster : 
3528
          #[ SortBotOut :
3529
*/
3530
 
3531
#ifdef WITHSORTBOTS
3532

3533
/**
3534
 *                This is the output routine of the SortBots.
3535
 *                It can run PutToMaster, except for the final merge.
3536
 *                In that case we need to do special things like calling PutOut.
3537
 *                Hence the first thing we have to do is to figure out where our
3538
 *                output should be going.
3539
 */
3540

3541
int
3542
SortBotOut(PHEAD WORD *term)
4,377,920✔
3543
{
3544
        WORD im;
4,377,920✔
3545

3546
        if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
4,377,920✔
3547

3548
        if ( term == 0 ) {
2,165,820✔
3549
                if ( FlushOut(&SortBotPosition,AR.outfile,1) ) return(-1);
823✔
3550
                ADDPOS(AT.SS->SizeInFile[0],1);
823✔
3551
                return(0);
823✔
3552
        }
3553
        else {
3554
                numberofterms++;
2,165,000✔
3555
                if ( ( im = PutOut(BHEAD term,&SortBotPosition,AR.outfile,1) ) < 0 ) {
2,165,000✔
3556
                        MLOCK(ErrorMessageLock);
×
3557
                        MesPrint("Called from MasterMerge/SortBotOut");
×
3558
                        MUNLOCK(ErrorMessageLock);
×
3559
                        return(-1);
×
3560
                }
3561
                ADDPOS(AT.SS->SizeInFile[0],im);
2,165,000✔
3562
                return(im);
2,165,000✔
3563
        }
3564
}
3565

3566
#endif
3567

3568
/*
3569
          #] SortBotOut : 
3570
          #[ MasterMerge :
3571
*/
3572
/**
3573
 *        This is the routine in which the master merges the sorted output that
3574
 *        comes from the workers. It is similar to MergePatches in sort.c from which
3575
 *        it takes much code.
3576
 *        The important concept here is that we want the master to be working as
3577
 *        little as possible because it constitutes the bottleneck.
3578
 *        The workers fill the buffers of the master. These buffers are divided
3579
 *        into parts for each worker as is done with the file patches in MergePatches
3580
 *        but now also each worker part is divided into blocks. This allows the
3581
 *        worker to fill blocks while the master is already working on blocks that
3582
 *        were filled before. The blocks are arranged in a circular fashion.
3583
 *        The whole is controlled by locks which seems faster than setting it up
3584
 *        with signals.
3585
 *
3586
 *        This routine is run by the master when we don't use the sortbots.
3587
 */
3588

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

3678
        Now construct the tree:
3679
*/
3680
        lpat = 1;
3681
        do { lpat <<= 1; } while ( lpat < S->lPatch );
823✔
3682
        mpat = ( lpat >> 1 ) - 1;
823✔
3683
        k = lpat - S->lPatch;
823✔
3684
/*
3685
        k is the number of empty places in the tree. they will
3686
        be at the even positions from 2 to 2*k
3687
*/
3688
        for ( i = 1; i < lpat; i++ ) { S->tree[i] = -1; }
1,646✔
3689
        for ( i = 1; i <= k; i++ ) {
823✔
3690
                im = ( i * 2 ) - 1;
×
3691
                poin[im] = AB[i]->T.SB.MasterStart[AB[i]->T.SB.MasterBlock];
×
3692
                poin2[im] = poin[im] + *(poin[im]);
×
3693
                S->used[i] = im;
×
3694
                S->ktoi[im] = i-1;
×
3695
                S->tree[mpat+i] = 0;
×
3696
                poin[im-1] = poin2[im-1] = 0;
×
3697
        }
3698
        for ( i = (k*2)+1; i <= lpat; i++ ) {
2,469✔
3699
                S->used[i-k] = i;
1,646✔
3700
                S->ktoi[i] = i-k-1;
1,646✔
3701
                poin[i] = AB[i-k]->T.SB.MasterStart[AB[i-k]->T.SB.MasterBlock];
1,646✔
3702
                poin2[i] = poin[i] + *(poin[i]);
1,646✔
3703
        }
3704
/*
3705
        the array poin tells the position of the i-th element of the S->tree
3706
        'S->used' is a stack with the S->tree elements that need to be entered
3707
        into the S->tree. at the beginning this is S->lPatch. during the
3708
        sort there will be only very few elements.
3709
        poin2 is the next value of poin. it has to be determined
3710
        before the comparisons as the position or the size of the
3711
        term indicated by poin may change.
3712
        S->ktoi translates a S->tree element back to its stream number.
3713

3714
        start the sort
3715
*/
3716
        level = S->lPatch;
823✔
3717
/*
3718
        introduce one term
3719
*/
3720
OneTerm:
2,217,030✔
3721
        k = S->used[level];
2,217,860✔
3722
        i = k + lpat - 1;
2,217,860✔
3723
        if ( !*(poin[k]) ) {
2,217,860✔
3724
                do { if ( !( i >>= 1 ) ) goto EndOfMerge; } while ( !S->tree[i] );
2,469✔
3725
                if ( S->tree[i] == -1 ) {
823✔
3726
                        S->tree[i] = 0;
642✔
3727
                        level--;
642✔
3728
                        goto OneTerm;
642✔
3729
                }
3730
                k = S->tree[i];
181✔
3731
                S->used[level] = k;
181✔
3732
                S->tree[i] = 0;
181✔
3733
        }
3734
/*
3735
        move terms down the tree
3736
*/
3737
        while ( i >>= 1 ) {
4,381,200✔
3738
                if ( S->tree[i] > 0 ) {
2,216,210✔
3739
                        if ( ( c = CompareTerms(B0, poin[S->tree[i]],poin[k],(WORD)0) ) > 0 ) {
43,066✔
3740
/*
3741
                                S->tree[i] is the smaller. Exchange and go on.
3742
*/
3743
                                S->used[level] = S->tree[i];
1,690✔
3744
                                S->tree[i] = k;
1,690✔
3745
                                k = S->used[level];
1,690✔
3746
                        }
3747
                        else if ( !c ) {        /* Terms are equal */
41,376✔
3748
/*
3749
                                S->TermsLeft--;
3750
                                        Here the terms are equal and their coefficients
3751
                                        have to be added.
3752
*/
3753
                                l1 = *( m1 = poin[S->tree[i]] );
25,993✔
3754
                                l2 = *( m2 = poin[k] );
25,993✔
3755
                                if ( S->PolyWise ) {  /* Here we work with PolyFun */
25,993✔
3756
                                        WORD *tt1, *w;
407✔
3757
                                        tt1 = m1;
407✔
3758
                                        m1 += S->PolyWise;
407✔
3759
                                        m2 += S->PolyWise;
407✔
3760
                                        if ( S->PolyFlag == 2 ) {
407✔
3761
                                                w = poly_ratfun_add(B0,m1,m2);
406✔
3762
                                                if ( *tt1 + w[1] - m1[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
406✔
3763
                                                        MLOCK(ErrorMessageLock);
×
3764
                                                        MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
3765
                                                        MUNLOCK(ErrorMessageLock);
×
3766
                                                        Terminate(-1);
×
3767
                                                }
3768
                                                AT0.WorkPointer = w;
406✔
3769
                                                if ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 && w[1] > FUNHEAD ) {
406✔
3770
                                                        goto cancelled;
403✔
3771
                                                }
3772
                                        }
3773
                                        else {
3774
                                                w = AT0.WorkPointer;
1✔
3775
                                                if ( w + m1[1] + m2[1] > AT0.WorkTop ) {
1✔
3776
                                                        MLOCK(ErrorMessageLock);
×
3777
                                                        MesPrint("MasterMerge: A WorkSpace of %10l is too small",AM.WorkSize);
×
3778
                                                        MUNLOCK(ErrorMessageLock);
×
3779
                                                        Terminate(-1);
×
3780
                                                }
3781
                                                AddArgs(B0,m1,m2,w);
1✔
3782
                                        }
3783
                                        r1 = w[1];
4✔
3784
                                        if ( r1 <= FUNHEAD
4✔
3785
                                                || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) )
4✔
3786
                                                         { goto cancelled; }
×
3787
                                        if ( r1 == m1[1] ) {
4✔
3788
                                                NCOPY(m1,w,r1);
50✔
3789
                                        }
3790
                                        else if ( r1 < m1[1] ) {
2✔
3791
                                                r2 = m1[1] - r1;
1✔
3792
                                                m2 = w + r1;
1✔
3793
                                                m1 += m1[1];
1✔
3794
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
81,140✔
3795
                                                m2 = m1 - r2;
1✔
3796
                                                r1 = S->PolyWise;
1✔
3797
                                                while ( --r1 >= 0 ) *--m1 = *--m2;
2✔
3798
                                                *m1 -= r2;
1✔
3799
                                                poin[S->tree[i]] = m1;
1✔
3800
                                        }
3801
                                        else {
3802
                                                r2 = r1 - m1[1];
1✔
3803
                                                m2 = tt1 - r2;
1✔
3804
                                                r1 = S->PolyWise;
1✔
3805
                                                m1 = tt1;
1✔
3806
                                                *m1 += r2;
1✔
3807
                                                poin[S->tree[i]] = m2;
1✔
3808
                                                NCOPY(m2,m1,r1);
2✔
3809
                                                r1 = w[1];
1✔
3810
                                                NCOPY(m2,w,r1);
32✔
3811
                                        }
3812
                                }
3813
#ifdef WITHFLOAT
3814
                                else if ( AT.SortFloatMode ) {
25,586✔
3815
                                        WORD *term1, *term2;
×
3816
                                        term1 = poin[S->tree[i]];
×
3817
                                        term2 = poin[k];
×
3818
                                        if ( MergeWithFloat(B0, &term1,&term2) == 0 )
×
3819
                                                goto cancelled;
×
3820
                                        poin[S->tree[i]] = term1;
×
3821
                                }
3822
#endif
3823
                                else {
3824
                                        r1 = *( m1 += l1 - 1 );
25,586✔
3825
                                        m1 -= ABS(r1) - 1;
25,586✔
3826
                                        r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
25,586✔
3827
                                        r2 = *( m2 += l2 - 1 );
25,586✔
3828
                                        m2 -= ABS(r2) - 1;
25,586✔
3829
                                        r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
25,586✔
3830

3831
                                        if ( AddRat(B0,(UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
25,586✔
3832
                                                MLOCK(ErrorMessageLock);
×
3833
                                                MesCall("MasterMerge");
×
3834
                                                MUNLOCK(ErrorMessageLock);
×
3835
                                                SETERROR(-1)
×
3836
                                        }
3837

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

4048
/*
4049
          #] MasterMerge : 
4050
          #[ SortBotMasterMerge :
4051
*/
4052
 
4053
#ifdef WITHSORTBOTS
4054

4055
/**
4056
 *        This is the master routine for the final stage in a sortbot merge.
4057
 *        A sortbot merge is a merge in which the output of two workers is
4058
 *        merged into a single output which then can be given as one of two
4059
 *        streams to another sortbot. The idea is that each sortbot is responsible
4060
 *        for one one compare per term. In the end the master does the last
4061
 *        merge of only two streams and writes the result to the output.
4062
 *        There doesn't seem to be an advantage to splitting this last task.
4063
 *
4064
 *        The use of the sortbots gives a measurable improvement but it isn't
4065
 *        optimal yet.
4066
 *
4067
 *        This routine is run as master. Hence B = B0. Etc.
4068
 */
4069

4070
int SortBotMasterMerge(VOID)
823✔
4071
{
4072
        FILEHANDLE *fin, *fout;
823✔
4073
        ALLPRIVATES *B = AB[0], *BB;
823✔
4074
        POSITION position;
823✔
4075
        SORTING *S = AT.SS;
823✔
4076
        int i, j;
823✔
4077
/*
4078
        Get the sortbots get to claim their writing blocks.
4079
        We have to wait till all have been claimed because they also have to
4080
        claim the last writing blocks of the workers to prevent the head of
4081
        the circular buffer to overrun the tail.
4082

4083
        Before waiting we can do some needed initializations.
4084
        Also the master has to claim the last writing blocks of its input.
4085
*/
4086
        topsortbotavailables = 0;
823✔
4087
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
2,469✔
4088
                WakeupThread(i,INISORTBOT);
1,646✔
4089
        }
4090

4091
        AS.MasterSort = 1;
823✔
4092
        fout = AR.outfile;
823✔
4093
        numberofterms = 0;
823✔
4094
        AR.CompressPointer[0] = 0;
823✔
4095
        numberclaimed = 0;
823✔
4096
        BB = AB[AT.SortBotIn1];
823✔
4097
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
823✔
4098
        BB = AB[AT.SortBotIn2];
823✔
4099
        LOCK(BB->T.SB.MasterBlockLock[BB->T.SB.MasterNumBlocks]);
823✔
4100

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

4168
        return(0);
823✔
4169
}
4170

4171
#endif
4172

4173
/*
4174
          #] SortBotMasterMerge : 
4175
          #[ SortBotMerge :
4176
*/
4177
 
4178
#ifdef WITHSORTBOTS
4179

4180
/**
4181
 *        This routine is run by a sortbot and merges two sorted output streams into
4182
 *        a single sorted stream.
4183
 */
4184

4185
int SortBotMerge(PHEAD0)
2,469✔
4186
{
4187
        GETBIDENTITY
4188
        ALLPRIVATES *Bin1 = AB[AT.SortBotIn1],*Bin2 = AB[AT.SortBotIn2];
2,469✔
4189
        WORD *term1, *term2, *next, *wp;
2,469✔
4190
        int blin1, blin2;        /* Current block numbers */
2,469✔
4191
        int error = 0;
2,469✔
4192
        WORD l1, l2, *m1, *m2, *w, r1, r2, r3, r33, r31, *tt1, ii;
2,469✔
4193
        WORD *to, *from, im, c;
2,469✔
4194
        UWORD *coef;
2,469✔
4195
        SORTING *S = AT.SS;
2,469✔
4196
#ifdef WITHFLOAT
4197
        WORD *fun1, *fun2, *fun3, *tstop1, *tstop2, size1, size2, size3, l3, jj, *m3;
2,469✔
4198
#endif
4199
/*
4200
        Set the pointers to the input terms and the output space
4201
*/
4202
        coef = AN.SoScratC;
2,469✔
4203
        blin1 = 1;
2,469✔
4204
        blin2 = 1;
2,469✔
4205
        if ( AT.identity == 0 ) {
2,469✔
4206
                wp = AT.WorkPointer;
823✔
4207
        }
4208
        else {
4209
                wp = AT.WorkPointer = AT.WorkSpace;
1,646✔
4210
        }
4211
/*
4212
        Get the locks for reading the input
4213
        This means that we can start once these locks have been cleared
4214
        which means that there will be input.
4215
*/
4216
        LOCK(Bin1->T.SB.MasterBlockLock[blin1]);
2,469✔
4217
        LOCK(Bin2->T.SB.MasterBlockLock[blin2]);
2,469✔
4218

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

4441
                                if ( l3 != l1 ) {
×
4442
/*
4443
                                        Copy it all to wp
4444
*/
4445
                                        if ( (l3)*((LONG)sizeof(WORD)) >= AM.MaxTer ) {
×
4446
                                                MLOCK(ErrorMessageLock);
×
4447
                                                MesPrint("MasterMerge: Coefficient overflow during sort");
×
4448
                                                MUNLOCK(ErrorMessageLock);
×
4449
                                                goto ReturnError;
×
4450
                                        }
4451
                    m3 = wp; m2 = term1;
4452
                                        while ( m2 < fun1 ) *m3++ = *m2++;
×
4453
                                        for ( jj = 0; jj < fun3[1]; jj++ ) *m3++ = fun3[jj];
×
4454
                                        *m3++ = 1; *m3++ = 1;
×
4455
                                        *m3++ = size3 < 0 ? -3: 3;
×
4456
                                        *wp = m3-wp;
×
4457
                                        TermFree(fun3,"MasterMerge");
×
4458
                                        goto PutOutwp;
×
4459
                                }
4460
                                for ( jj = 0; jj < fun3[1]; jj++ ) fun1[jj] = fun3[jj];
×
4461
                                fun1 += fun3[1];
×
4462
                                *fun1++ = 1; *fun1++ = 1;
×
4463
                                *fun1++ = size3 < 0 ? -3: 3;
×
4464
                                *term1 = fun1-term1;
×
4465
                                TermFree(fun3,"MasterMerge");
×
4466
                        }
4467
#endif
4468
                        else {
4469
                                r1 = *( m1 += l1 - 1 );
36,058✔
4470
                                m1 -= ABS(r1) - 1;
36,058✔
4471
                                r1 = ( ( r1 > 0 ) ? (r1-1) : (r1+1) ) >> 1;
36,058✔
4472
                                r2 = *( m2 += l2 - 1 );
36,058✔
4473
                                m2 -= ABS(r2) - 1;
36,058✔
4474
                                r2 = ( ( r2 > 0 ) ? (r2-1) : (r2+1) ) >> 1;
36,058✔
4475

4476
                                if ( AddRat(BHEAD (UWORD *)m1,r1,(UWORD *)m2,r2,coef,&r3) ) {
36,058✔
4477
                                        MLOCK(ErrorMessageLock);
×
4478
                                        MesCall("SortBotMerge");
×
4479
                                        MUNLOCK(ErrorMessageLock);
×
4480
                                        SETERROR(-1)
×
4481
                                }
4482

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

4683
#endif
4684

4685
/*
4686
          #] SortBotMerge : 
4687
          #[ IniSortBlocks :
4688
*/
4689
 
4690
static int SortBlocksInitialized = 0;
4691

4692
/**
4693
 *        Initializes the blocks in the sort buffers of the master.
4694
 *        These blocks are needed to keep both the workers and the master working
4695
 *        simultaneously. See also the commentary at the routine MasterMerge.
4696
 */
4697

4698
int IniSortBlocks(int numworkers)
506✔
4699
{
4700
        ALLPRIVATES *B;
506✔
4701
        SORTING *S;
506✔
4702
        LONG totalsize, workersize, blocksize, numberofterms;
506✔
4703
        int maxter, id, j;
506✔
4704
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
506✔
4705
        WORD *w;
506✔
4706

4707
        if ( SortBlocksInitialized ) return(0);
506✔
4708
        SortBlocksInitialized = 1;
506✔
4709
        if ( numworkers == 0 ) return(0);
506✔
4710

4711
#ifdef WITHSORTBOTS
4712
        if ( numworkers > 2 ) {
504✔
4713
                numparts = 2*numworkers - 2;
252✔
4714
                numberofblocks = numberofblocks/2;
252✔
4715
        }
4716
        else {
4717
                numparts = numworkers;
4718
        }
4719
#else
4720
        numparts = numworkers;
4721
#endif
4722
        S = AM.S0;
504✔
4723
        totalsize = S->LargeSize + S->SmallEsize;
504✔
4724
        workersize = totalsize / numparts;
504✔
4725
        maxter = AM.MaxTer/sizeof(WORD);
504✔
4726
        blocksize = ( workersize - maxter )/numberofblocks;
504✔
4727
        numberofterms = blocksize / maxter;
504✔
4728
        if ( numberofterms < MINIMUMNUMBEROFTERMS ) {
504✔
4729
/*
4730
                This should have been taken care of in RecalcSetups.
4731
*/
4732
                MesPrint("We have a problem with the size of the blocks in IniSortBlocks");
×
4733
                Terminate(-1);
×
4734
        }
4735
/*
4736
        Layout:  For each worker
4737
                                block 0: size is maxter WORDS
4738
                                numberofblocks blocks of size blocksize WORDS
4739
*/
4740
        w = S->lBuffer;
504✔
4741
        if ( w == 0 ) w = S->sBuffer;
504✔
4742
        for ( id = 1; id <= numparts; id++ ) {
2,520✔
4743
                B = AB[id];
2,016✔
4744
                AT.SB.MasterBlockLock = (pthread_mutex_t *)Malloc1(
4,032✔
4745
                        sizeof(pthread_mutex_t)*(numberofblocks+1),"MasterBlockLock");
2,016✔
4746
                AT.SB.MasterStart = (WORD **)Malloc1(sizeof(WORD *)*(numberofblocks+1)*3,"MasterBlock");
2,016✔
4747
                AT.SB.MasterFill = AT.SB.MasterStart + (numberofblocks+1);
2,016✔
4748
                AT.SB.MasterStop = AT.SB.MasterFill  + (numberofblocks+1);
2,016✔
4749
                AT.SB.MasterNumBlocks = numberofblocks;
2,016✔
4750
                AT.SB.MasterBlock = 0;
2,016✔
4751
                AT.SB.FillBlock = 0;
2,016✔
4752
                AT.SB.MasterFill[0] = AT.SB.MasterStart[0] = w;
2,016✔
4753
                w += maxter;
2,016✔
4754
                AT.SB.MasterStop[0] = w;
2,016✔
4755
                AT.SB.MasterBlockLock[0] = dummylock;
2,016✔
4756
                for ( j = 1; j <= numberofblocks; j++ ) {
14,616✔
4757
                        AT.SB.MasterFill[j] = AT.SB.MasterStart[j] = w;
12,600✔
4758
                        w += blocksize;
12,600✔
4759
                        AT.SB.MasterStop[j] = w;
12,600✔
4760
                        AT.SB.MasterBlockLock[j] = dummylock;
12,600✔
4761
                }
4762
        }
4763
        if ( w > S->sTop2 ) {
504✔
4764
                MesPrint("Counting problem in IniSortBlocks");
×
4765
                Terminate(-1);
×
4766
        }
4767
        return(0);
4768
}
4769

4770
/*
4771
          #] IniSortBlocks : 
4772
          #[ DefineSortBotTree :
4773
*/
4774
 
4775
#ifdef WITHSORTBOTS
4776

4777
/**
4778
 *        To be used in a sortbot merge. It initializes the whole sortbot
4779
 *        system by telling the sortbot which threads provide their input.
4780
 */
4781

4782
void DefineSortBotTree(VOID)
506✔
4783
{
4784
        ALLPRIVATES *B;
506✔
4785
        int n, i, from;
506✔
4786
        if ( numberofworkers <= 2 ) return;
506✔
4787
        n = numberofworkers*2-2;
252✔
4788
        for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
756✔
4789
                B = AB[i];
504✔
4790
                AT.SortBotIn1 = from++;
504✔
4791
                AT.SortBotIn2 = from++;
504✔
4792
        }
4793
        B = AB[0];
252✔
4794
        AT.SortBotIn1 = from++;
252✔
4795
        AT.SortBotIn2 = from++;
252✔
4796
}
4797

4798
#endif
4799

4800
/*
4801
          #] DefineSortBotTree : 
4802
          #[ GetTerm2 :
4803

4804
        Routine does a GetTerm but only when a bracket index is involved and
4805
        only from brackets that have been judged not suitable for treatment
4806
        as complete brackets by a single worker. Whether or not a bracket should
4807
        be treated by a single worker is decided by TreatIndexEntry
4808
*/
4809

4810
WORD GetTerm2(PHEAD WORD *term)
1,816✔
4811
{
4812
        WORD *ttco, *tt, retval;
1,816✔
4813
        LONG n,i;
1,816✔
4814
        FILEHANDLE *fi;
1,816✔
4815
        EXPRESSIONS e = AN.expr;
1,816✔
4816
        BRACKETINFO *b  = e->bracketinfo;
1,816✔
4817
        BRACKETINDEX *bi = b->indexbuffer;
1,816✔
4818
        POSITION where, eonfile = AS.OldOnFile[e-Expressions], bstart, bnext;
1,816✔
4819
/*
4820
        1: Get the current position.
4821
*/
4822
        switch ( e->status ) {
1,816✔
4823
                case UNHIDELEXPRESSION:
×
4824
                case UNHIDEGEXPRESSION:
4825
                case DROPHLEXPRESSION:
4826
                case DROPHGEXPRESSION:
4827
                case HIDDENLEXPRESSION:
4828
                case HIDDENGEXPRESSION:
4829
                        fi = AR.hidefile;
×
4830
                        break;
×
4831
                default:
1,816✔
4832
                        fi = AR.infile;
1,816✔
4833
                        break;
1,816✔
4834
        }
4835
        if ( AR.KeptInHold ) {
1,816✔
4836
                retval = GetTerm(BHEAD term);
3✔
4837
                return(retval);
3✔
4838
        }
4839
        SeekScratch(fi,&where);
1,813✔
4840
        if ( AN.lastinindex < 0 ) {
1,813✔
4841
/*
4842
                We have to test whether we have to do the first bracket
4843
*/
4844
                if ( ( n = TreatIndexEntry(BHEAD 0) ) <= 0 ) {
3✔
4845
                        AN.lastinindex = n;
×
4846
                        where = bi[n].start;
×
4847
                        ADD2POS(where,eonfile);
×
4848
                        SetScratch(fi,&where);
×
4849
/*
4850
                        Put the bracket in the Compress buffer.
4851
*/
4852
                        ttco = AR.CompressBuffer;
×
4853
                        tt = b->bracketbuffer + bi[0].bracket;
×
4854
                        i = *tt;
×
4855
                        NCOPY(ttco,tt,i)
×
4856
                        AR.CompressPointer = ttco;
×
4857
                        retval = GetTerm(BHEAD term);
×
4858
                        return(retval);
×
4859
                }
4860
                else AN.lastinindex = n-1;
3✔
4861
        }
4862
/*
4863
        2: Find the corresponding index number
4864
           a: test whether it is in the current bracket
4865
*/
4866
        n = AN.lastinindex;
1,813✔
4867
        bstart = bi[n].start;
1,813✔
4868
        ADD2POS(bstart,eonfile);
1,813✔
4869
        bnext = bi[n].next;
1,813✔
4870
        ADD2POS(bnext,eonfile);
1,813✔
4871
        if ( ISLESSPOS(bstart,where) && ISLESSPOS(where,bnext) ) {
1,813✔
4872
                retval = GetTerm(BHEAD term);
1,786✔
4873
                return(retval);
1,786✔
4874
        }
4875
        for ( n++ ; n < b->indexfill; n++ ) {
77✔
4876
                i = TreatIndexEntry(BHEAD n);
72✔
4877
                if ( i <= 0 ) {
72✔
4878
/*
4879
                        Put the bracket in the Compress buffer.
4880
*/
4881
                        ttco = AR.CompressBuffer;
22✔
4882
                        tt = b->bracketbuffer + bi[n].bracket;
22✔
4883
                        i = *tt;
22✔
4884
                        NCOPY(ttco,tt,i)
282✔
4885
                        AR.CompressPointer = ttco;
22✔
4886
                        AN.lastinindex = n;
22✔
4887
                        where = bi[n].start;
22✔
4888
                        ADD2POS(where,eonfile);
22✔
4889
                        SetScratch(fi,&(where));
22✔
4890
                        retval = GetTerm(BHEAD term);
22✔
4891
                        return(retval);
22✔
4892
                }
4893
                else n += i - 1;
50✔
4894
        }
4895
        return(0);
4896
}
4897

4898
/*
4899
          #] GetTerm2 : 
4900
          #[ TreatIndexEntry :
4901
*/
4902
/**
4903
 *        Routine has to decide whether a bracket has to be sent as a complete
4904
 *        bracket to a worker or whether it has to be treated by the bucket system.
4905
 *        Return value is positive when we should send it as a complete bracket and
4906
 *        0 when it should be done via the buckets.
4907
 *        The positive return value indicates how many brackets should be treated.
4908
 */
4909
 
4910
int TreatIndexEntry(PHEAD LONG n)
204✔
4911
{
4912
        BRACKETINFO *b  = AN.expr->bracketinfo;
204✔
4913
        LONG numbra = b->indexfill - 1, i;
204✔
4914
        LONG totterms;
204✔
4915
        BRACKETINDEX *bi;
204✔
4916
        POSITION pos1, average;
204✔
4917
/*
4918
        1: number of the bracket should be such that there is one bucket
4919
           for each worker remaining.
4920
*/
4921
        if ( ( numbra - n ) <= numberofworkers ) return(0);
204✔
4922
/*
4923
        2: size of the bracket contents should be less than what remains in
4924
           the expression divided by the number of workers.
4925
*/
4926
        bi = b->indexbuffer;
133✔
4927
        DIFPOS(pos1,bi[numbra].next,bi[n].next);  /* Size of what remains */
133✔
4928
        BASEPOSITION(average) = DIVPOS(pos1,(3*numberofworkers));
133✔
4929
        DIFPOS(pos1,bi[n].next,bi[n].start);      /* Size of the current bracket */
133✔
4930
        if ( ISLESSPOS(average,pos1) ) return(0);
133✔
4931
/*
4932
        It passes.
4933
        Now check whether we can do more brackets
4934
*/
4935
        totterms = bi->termsinbracket;
106✔
4936
        if ( totterms > 2*AC.ThreadBucketSize ) return(1);
106✔
4937
        for ( i = 1; i < numbra-n; i++ ) {
360✔
4938
                DIFPOS(pos1,bi[n+i].next,bi[n].start); /* Size of the combined brackets */
360✔
4939
                if ( ISLESSPOS(average,pos1) ) return(i);
360✔
4940
                totterms += bi->termsinbracket;
262✔
4941
                if ( totterms > 2*AC.ThreadBucketSize ) return(i+1);
262✔
4942
        }
4943
/*
4944
        We have a problem at the end of the system. Just do one.
4945
*/
4946
        return(1);
4947
}
4948

4949
/*
4950
          #] TreatIndexEntry : 
4951
          #[ SetHideFiles :
4952
*/
4953

4954
void SetHideFiles(VOID) {
28✔
4955
        int i;
28✔
4956
        ALLPRIVATES *B, *B0 = AB[0];
28✔
4957
        for ( i = 1; i <= numberofworkers; i++ ) {
112✔
4958
                B = AB[i];
84✔
4959
                AR.hidefile->handle = AR0.hidefile->handle;
84✔
4960
                if ( AR.hidefile->handle < 0 ) {
84✔
4961
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
84✔
4962
                        AR.hidefile->POstop = AR0.hidefile->POstop;
84✔
4963
                        AR.hidefile->POfill = AR0.hidefile->POfill;
84✔
4964
                        AR.hidefile->POfull = AR0.hidefile->POfull;
84✔
4965
                        AR.hidefile->POsize = AR0.hidefile->POsize;
84✔
4966
                        AR.hidefile->POposition = AR0.hidefile->POposition;
84✔
4967
                        AR.hidefile->filesize = AR0.hidefile->filesize;
84✔
4968
                }
4969
                else {
4970
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
4971
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
4972
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
4973
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
4974
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
4975
                        PUTZERO(AR.hidefile->POposition);
×
4976
                }
4977
        }
4978
}
28✔
4979

4980
/*
4981
          #] SetHideFiles : 
4982
          #[ IniFbufs :
4983
*/
4984

4985
void IniFbufs(VOID)
506✔
4986
{
4987
        int i;
506✔
4988
        for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
2,524✔
4989
                IniFbuffer(AB[i]->T.fbufnum);
2,018✔
4990
        }
4991
}
506✔
4992

4993
/*
4994
          #] IniFbufs : 
4995
          #[ SetMods :
4996
*/
4997

4998
void SetMods(VOID)
2✔
4999
{
5000
        ALLPRIVATES *B;
2✔
5001
        int i, n, j;
2✔
5002
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
10✔
5003
                B = AB[j];
8✔
5004
                AN.ncmod = AC.ncmod;
8✔
5005
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
8✔
5006
                n = ABS(AN.ncmod);
8✔
5007
                AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
8✔
5008
                for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
16✔
5009
        }
5010
}
2✔
5011

5012
/*
5013
          #] SetMods : 
5014
          #[ UnSetMods :
5015
*/
5016

5017
void UnSetMods(VOID)
2✔
5018
{
5019
        ALLPRIVATES *B;
2✔
5020
        int j;
2✔
5021
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
10✔
5022
                B = AB[j];
8✔
5023
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
8✔
5024
                AN.cmod = 0;
8✔
5025
        }
5026
}
2✔
5027

5028
/*
5029
          #] UnSetMods : 
5030
          #[ find_Horner_MCTS_expand_tree_threaded :
5031
*/
5032
 
5033
void find_Horner_MCTS_expand_tree_threaded(VOID) {
59✔
5034
        int id;
59✔
5035
        while (( id = GetAvailableThread() ) < 0)
89✔
5036
                MasterWait();        
30✔
5037
        WakeupThread(id,MCTSEXPANDTREE);
59✔
5038
}
59✔
5039

5040
/*
5041
          #] find_Horner_MCTS_expand_tree_threaded : 
5042
          #[ optimize_expression_given_Horner_threaded :
5043
*/
5044
 
5045
extern void optimize_expression_given_Horner_threaded(VOID) {
26✔
5046
        int id;
26✔
5047
        while (( id = GetAvailableThread() ) < 0)
26✔
5048
                MasterWait();        
×
5049
        WakeupThread(id,OPTIMIZEEXPRESSION);
26✔
5050
}
26✔
5051

5052
/*
5053
          #] optimize_expression_given_Horner_threaded : 
5054
*/
5055

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

© 2025 Coveralls, Inc