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

tueda / form / 13008440788

28 Jan 2025 10:28AM UTC coverage: 50.721% (+0.007%) from 50.714%
13008440788

push

github

tueda
feat: add runtime deprecation warnings

FORM prints deprecation warnings at startup for native Windows, 32-bit
(ILP32) and ParFORM (MPI) versions, as well as for the use of the
checkpoint mechanism. This encourages users who need support for these
deprecated features to leave a comment on the corresponding GitHub
issues.

The warnings can be suppressed by using the -ignore-deprecation
command-line option or by setting the environment variable
FORM_IGNORE_DEPRECATION=1.

7 of 26 new or added lines in 3 files covered. (26.92%)

8 existing lines in 1 file now uncovered.

42086 of 82976 relevant lines covered (50.72%)

1399922.64 hits per line

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

77.56
/sources/threads.c
1
/** @file threads.c
2
 * 
3
 *  Routines for the interface of FORM with the pthreads library
4
 *
5
 *        This is the main part of the parallelization of TFORM.
6
 *        It is important to also look in the files structs.h and variable.h
7
 *        because the treatment of the A and B structs is essential (these
8
 *        structs are used by means of the macros AM, AP, AC, AS, AR, AT, AN,
9
 *        AO and AX). Also the definitions and use of the macros BHEAD and PHEAD
10
 *        should be looked up.
11
 *
12
 *        The sources are set up in such a way that if WITHPTHREADS isn't defined
13
 *        there is no trace of pthread parallelization.
14
 *        The reason is that TFORM is far more memory hungry than sequential FORM.
15
 *
16
 *        Special attention should also go to the locks. The proper use of the
17
 *        locks is essential and determines whether TFORM can work at all.
18
 *        We use the LOCK/UNLOCK macros which are empty in the case of sequential FORM
19
 *        These locks are at many places in the source files when workers can
20
 *        interfere with each others data or with the data of the master.
21
 */
22
/* #[ License : */
23
/*
24
 *   Copyright (C) 1984-2023 J.A.M. Vermaseren
25
 *   When using this file you are requested to refer to the publication
26
 *   J.A.M.Vermaseren "New features of FORM" math-ph/0010025
27
 *   This is considered a matter of courtesy as the development was paid
28
 *   for by FOM the Dutch physics granting agency and we would like to
29
 *   be able to track its scientific use to convince FOM of its value
30
 *   for the community.
31
 *
32
 *   This file is part of FORM.
33
 *
34
 *   FORM is free software: you can redistribute it and/or modify it under the
35
 *   terms of the GNU General Public License as published by the Free Software
36
 *   Foundation, either version 3 of the License, or (at your option) any later
37
 *   version.
38
 *
39
 *   FORM is distributed in the hope that it will be useful, but WITHOUT ANY
40
 *   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
41
 *   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
42
 *   details.
43
 *
44
 *   You should have received a copy of the GNU General Public License along
45
 *   with FORM.  If not, see <http://www.gnu.org/licenses/>.
46
 */
47
/* #] License : */ 
48
 
49
#ifdef WITHPTHREADS
50

51
#define WHOLEBRACKETS
52
/*
53
          #[ Variables :
54

55
        The sortbot additions are from 17-may-2007 and after. They constitute
56
        an attempt to make the final merge sorting faster for the master.
57
        This way the master has only one compare per term.
58
        It does add some complexity, but the final merge routine (MasterMerge)
59
        is much simpler for the sortbots. On the other hand the original merging is
60
        for a large part a copy of the MergePatches routine in sort.c and hence
61
        even though complex the bad part has been thoroughly debugged.
62
*/
63

64
#include "form3.h"
65
#ifdef WITHFLOAT
66
#include <gmp.h>
67

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

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

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

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

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

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

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

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

140
void FinishIdentity(void *keyp)
2,032✔
141
{
142
        DUMMYUSE(keyp);
2,032✔
143
/*        free(keyp); */
144
}
2,032✔
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,856✔
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,856✔
163
        *identityretval = identityofthreads++;
2,856✔
164
        UNLOCK(numberofthreadslock);
2,856✔
165
        pthread_setspecific(identitykey,(void *)identityretval);
2,856✔
166
        return(*identityretval);
2,856✔
167
}
168

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

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

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

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

197
        but according to the information in pthread.h it is:
198
*/
199
        identity = (int *)pthread_getspecific(identitykey);
35,667,800✔
200
        return(*identity);
35,667,800✔
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)
576✔
213
{
214
        StartIdentity();
576✔
215
        SetIdentity(&identityretval);
576✔
216
}
576✔
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)
576✔
230
{
231
        AM.handlelock = dummyrwlock;
576✔
232
}
576✔
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)
574✔
256
{
257
        int identity, j, dummy, mul;
574✔
258
        ALLPRIVATES *B;
574✔
259
        pthread_t thethread;
574✔
260
        identity = WhoAmI();
574✔
261

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

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

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

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

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

397
        bsize = sizeof(ALLPRIVATES);
2,854✔
398
        bsize = (bsize+sizeof(int)-1)/sizeof(int);
2,854✔
399
        B = (ALLPRIVATES *)Malloc1(sizeof(int)*bsize,"B struct");
2,854✔
400
        for ( bp = (int *)B, j = 0; j < bsize; j++ ) *bp++ = 0;
16,992,680✔
401

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

421
#ifdef WITHSORTBOTS
422

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

832
VOID TerminateAllThreads(VOID)
512✔
833
{
834
        int i;
512✔
835
        for ( i = 1; i <= numberofworkers; i++ ) {
2,036✔
836
                GetThread(i);
1,524✔
837
                WakeupThread(i,TERMINATETHREAD);
1,524✔
838
        }
839
#ifdef WITHSORTBOTS
840
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
1,020✔
841
                WakeupThread(i,TERMINATETHREAD);
508✔
842
        }
843
#endif
844
        for ( i = 1; i <= numberofworkers; i++ ) {
2,036✔
845
                pthread_join(threadpointers[i],NULL);
1,524✔
846
        }
847
#ifdef WITHSORTBOTS
848
        for ( i = numberofworkers+1; i <= numberofworkers+numberofsortbots; i++ ) {
1,020✔
849
                pthread_join(threadpointers[i],NULL);
508✔
850
        }
851
#endif
852
}
512✔
853

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1163
        WakeupThread(identity,HIGHERLEVELGENERATION);
×
1164

1165
        return(0);
×
1166
}
1167

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

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

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

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

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

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

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

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

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

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

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

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

1772
                                AT.WorkPointer = oldwork;
2✔
1773

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

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

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

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

1918
#ifdef WITHSORTBOTS
1919

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

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

2007
#endif
2008

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

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

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

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

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

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

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

2116
int GetThread(int identity)
27,282✔
2117
{
2118
        int retval = -1, j;
27,282✔
2119
        LOCK(availabilitylock);
27,282✔
2120
        for ( j = 0; j < topofavailables; j++ ) {
74,270✔
2121
                if ( identity == listofavailables[j] ) break;
46,988✔
2122
        }
2123
        if ( j < topofavailables ) {
27,282✔
2124
                --topofavailables;
27,282✔
2125
                for ( ; j < topofavailables; j++ ) {
39,996✔
2126
                        listofavailables[j] = listofavailables[j+1];
12,714✔
2127
                }
2128
                retval = identity;
2129
        }
2130
        UNLOCK(availabilitylock);
27,282✔
2131
        return(retval);
27,282✔
2132
}
2133

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

2147
int ThreadWait(int identity)
55,290✔
2148
{
2149
        int retval, top, j;
55,290✔
2150
        LOCK(wakeuplocks[identity]);
55,290✔
2151
        LOCK(availabilitylock);
55,290✔
2152
        top = topofavailables;
55,290✔
2153
        for ( j = topofavailables; j > 0; j-- )
116,795✔
2154
                listofavailables[j] = listofavailables[j-1];
61,505✔
2155
        listofavailables[0] = identity;
55,290✔
2156
        topofavailables++;
55,290✔
2157
        if ( top == 0 || topofavailables == numberofworkers ) {
55,290✔
2158
                UNLOCK(availabilitylock);
38,396✔
2159
                LOCK(wakeupmasterlock);
38,396✔
2160
                wakeupmaster = identity;
38,396✔
2161
                pthread_cond_signal(&wakeupmasterconditions);
38,396✔
2162
                UNLOCK(wakeupmasterlock);
38,396✔
2163
        }
2164
        else {
2165
                UNLOCK(availabilitylock);
16,894✔
2166
        }
2167
        while ( wakeup[identity] == 0 ) {
110,438✔
2168
                pthread_cond_wait(&(wakeupconditions[identity]),&(wakeuplocks[identity]));
55,290✔
2169
        }
2170
        retval = wakeup[identity];
55,148✔
2171
        wakeup[identity] = 0;
55,148✔
2172
        UNLOCK(wakeuplocks[identity]);
55,148✔
2173
        return(retval);
55,148✔
2174
}
2175

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

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

2216
#endif
2217

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

2232
int ThreadClaimedBlock(int identity)
12,882✔
2233
{
2234
        LOCK(availabilitylock);
12,882✔
2235
        numberclaimed++;        
12,882✔
2236
        if ( numberclaimed >= numberofworkers ) {
12,882✔
2237
                UNLOCK(availabilitylock);
4,294✔
2238
                LOCK(wakeupmasterlock);
4,294✔
2239
                wakeupmaster = identity;
4,294✔
2240
                pthread_cond_signal(&wakeupmasterconditions);
4,294✔
2241
                UNLOCK(wakeupmasterlock);
4,294✔
2242
        }
2243
        else {
2244
                UNLOCK(availabilitylock);
8,588✔
2245
        }
2246
        return(0);
12,882✔
2247
}
2248

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

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

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

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

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

2307
void MasterWaitAll(VOID)
17,872✔
2308
{
2309
        LOCK(wakeupmasterlock);
17,872✔
2310
        while ( topofavailables < numberofworkers ) {
32,781✔
2311
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
14,947✔
2312
        }
2313
        UNLOCK(wakeupmasterlock);
17,834✔
2314
        return;
17,834✔
2315
}
2316

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

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

2329
void MasterWaitAllSortBots(VOID)
4,867✔
2330
{
2331
        LOCK(wakeupsortbotlock);
4,867✔
2332
        while ( topsortbotavailables < numberofsortbots ) {
7,299✔
2333
                pthread_cond_wait(&wakeupsortbotconditions,&wakeupsortbotlock);
2,432✔
2334
        }
2335
        UNLOCK(wakeupsortbotlock);
4,867✔
2336
        return;
4,867✔
2337
}
2338

2339
#endif
2340

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

2351
void MasterWaitAllBlocks(VOID)
4,294✔
2352
{
2353
        LOCK(wakeupmasterlock);
4,294✔
2354
        while ( numberclaimed < numberofworkers ) {
9,119✔
2355
                pthread_cond_wait(&wakeupmasterconditions,&wakeupmasterlock);
4,825✔
2356
        }
2357
        UNLOCK(wakeupmasterlock);
4,294✔
2358
        return;
4,294✔
2359
}
2360

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2927
                        All threads are busy. Try to load up another bucket.
2928
                        In the future we could be more sophisticated.
2929
                        At the moment we load a complete bucket which could be
2930
                        1000 terms or even more.
2931
                        In principle it is better to keep a full bucket ready
2932
                        and check after each term we put in the next bucket. That
2933
                        way we don't waste time of the workers.
2934
*/
2935
                        for ( j = 0; j < numthreadbuckets; j++ ) {
44,261✔
2936
                                switch ( threadbuckets[j]->free ) {
40,431✔
2937
                                        case BUCKETFREE:
2938
                                                thr = threadbuckets[j];
3,869✔
2939
                                                if ( !endofinput ) goto NextBucket;
3,869✔
2940
/*
2941
                                                If we are at the end of the input we mark
2942
                                                the free buckets in a special way. That way
2943
                                                we don't keep running into them.
2944
*/
2945
                                                thr->free = BUCKETATEND;
2946
                                                break;
2947
                                        case BUCKETCOMINGFREE:
372✔
2948
                                                thr = threadbuckets[j];
372✔
2949
                                                thr->free = BUCKETFREE;
372✔
2950
/*
2951
                                                Bucket has just been finished.
2952
                                                Put at the end of the list. We don't want
2953
                                                an early bucket to wait to be treated last.
2954
*/
2955
                                                for ( k = j+1; k < numthreadbuckets; k++ )
2,239✔
2956
                                                        threadbuckets[k-1] = threadbuckets[k];
1,867✔
2957
                                                threadbuckets[numthreadbuckets-1] = thr;
372✔
2958
                                                j--;   /* we have to redo the same number j. */
372✔
2959
                                                break;
372✔
2960
                                        default:
2961
                                                break;
2962
                                }
2963
                        }
2964
/*
2965
                        We have no free bucket or we are at the end.
2966
                        The only thing we can do now is wait for a worker to come free,
2967
                        provided there are still buckets to send.
2968
*/
2969
                }
2970
/*
2971
                Look for the next bucket to send. There is at least one full bucket!
2972
*/
2973
                for ( j = 0; j < numthreadbuckets; j++ ) {
15,681✔
2974
                        if ( threadbuckets[j]->free == BUCKETFILLED ) {
15,681✔
2975
                                thr = threadbuckets[j];
10,298✔
2976
                                for ( k = j+1; k < numthreadbuckets; k++ )
57,621✔
2977
                                        threadbuckets[k-1] = threadbuckets[k];
47,323✔
2978
                                threadbuckets[numthreadbuckets-1] = thr;
10,298✔
2979
                                break;
10,298✔
2980
                        }
2981
                }
2982
/*
2983
                Wait for a thread to become available
2984
                The bucket we are going to use is in thr.
2985
*/
2986
DoBucket:;
11,342✔
2987
                AN0.ninterms++;
14,426✔
2988
                while ( ( id = GetAvailableThread() ) < 0 ) { MasterWait(); }
20,713✔
2989
/*
2990
                Prepare the thread. Give it the term and variables.
2991
*/
2992
                LoadOneThread(0,id,thr,0);
14,426✔
2993
                LOCK(thr->lock);
14,426✔
2994
                thr->busy = BUCKETASSIGNED;
14,426✔
2995
                UNLOCK(thr->lock);
14,426✔
2996
                thr->free = BUCKETINUSE;
14,426✔
2997
                numberoffullbuckets--;
14,426✔
2998
/*
2999
                And signal the thread to run.
3000
                Form now on we may only interfere with this bucket
3001
                1: after it has been marked BUCKETCOMINGFREE
3002
                2: when thr->busy == BUCKETDOINGTERM and then only when protected by
3003
                   thr->lock. This would be for load balancing.
3004
*/
3005
                WakeupThread(id,LOWESTLEVELGENERATION);
14,426✔
3006
/*                AN0.ninterms += thr->ddterms; */
3007
/*
3008
                Now look whether there is another bucket filled and a worker available
3009
*/
3010
                if ( topofavailables > 0 ) {  /* there is a worker */
14,426✔
3011
                        for ( j = 0; j < numthreadbuckets; j++ ) {
52,870✔
3012
                                if ( threadbuckets[j]->free == BUCKETFILLED ) {
46,980✔
3013
                                        thr = threadbuckets[j];
3,084✔
3014
                                        for ( k = j+1; k < numthreadbuckets; k++ )
13,960✔
3015
                                                threadbuckets[k-1] = threadbuckets[k];
10,876✔
3016
                                        threadbuckets[numthreadbuckets-1] = thr;
3,084✔
3017
                                        goto DoBucket; /* and we found a bucket */
3,084✔
3018
                                }
3019
                        }
3020
/*
3021
                        no bucket is loaded but there is a thread available
3022
                        find a bucket to load. If there is none (all are USED or ATEND)
3023
                        we jump out of the loop.
3024
*/
3025
                        for ( j = 0; j < numthreadbuckets; j++ ) {
10,292✔
3026
                                switch ( threadbuckets[j]->free ) {
9,764✔
3027
                                        case BUCKETFREE:
5,412✔
3028
                                                thr = threadbuckets[j];
5,412✔
3029
                                                if ( !endofinput ) goto NextBucket;
5,412✔
3030
                                                thr->free = BUCKETATEND;
50✔
3031
                                                break;
50✔
3032
                                        case BUCKETCOMINGFREE:
2,081✔
3033
                                                thr = threadbuckets[j];
2,081✔
3034
                                                if ( endofinput ) {
2,081✔
3035
                                                        thr->free = BUCKETATEND;
1,254✔
3036
                                                }
3037
                                                else {
3038
                                                        thr->free = BUCKETFREE;
827✔
3039
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
5,422✔
3040
                                                                threadbuckets[k-1] = threadbuckets[k];
4,595✔
3041
                                                        threadbuckets[numthreadbuckets-1] = thr;
827✔
3042
                                                        j--;
827✔
3043
                                                }
3044
                                                break;
3045
                                        default:
3046
                                                break;
3047
                                }
3048
                        }
3049
                        if ( j >= numthreadbuckets ) break;
528✔
3050
                }
3051
                else {
3052
/*
3053
                        No worker available.
3054
                        Look for a bucket to load.
3055
                        Its number will be in "still"
3056
*/
3057
Finalize:;
5,452✔
3058
                        still = -1;
50,992✔
3059
                        for ( j = 0; j < numthreadbuckets; j++ ) {
410,575✔
3060
                                switch ( threadbuckets[j]->free ) {
364,411✔
3061
                                        case BUCKETFREE:
24,010✔
3062
                                                thr = threadbuckets[j];
24,010✔
3063
                                                if ( !endofinput ) goto NextBucket;
24,010✔
3064
                                                thr->free = BUCKETATEND;
19,182✔
3065
                                                break;
19,182✔
3066
                                        case BUCKETCOMINGFREE:
6,978✔
3067
                                                thr = threadbuckets[j];
6,978✔
3068
                                                if ( endofinput ) thr->free = BUCKETATEND;
6,978✔
3069
                                                else {
3070
                                                        thr->free = BUCKETFREE;
6,220✔
3071
                                                        for ( k = j+1; k < numthreadbuckets; k++ )
35,934✔
3072
                                                                threadbuckets[k-1] = threadbuckets[k];
29,714✔
3073
                                                        threadbuckets[numthreadbuckets-1] = thr;
6,220✔
3074
                                                        j--;
6,220✔
3075
                                                }
3076
                                                break;
3077
                                        case BUCKETFILLED:
6,786✔
3078
                                                if ( still < 0 ) still = j;
6,786✔
3079
                                                break;
3080
                                        default:
3081
                                                break;
3082
                                }
3083
                        }
3084
                        if ( still < 0 ) {
46,164✔
3085
/*
3086
                                No buckets to be executed and no buckets FREE.
3087
                                We must be at the end. Break out of the loop.
3088
*/
3089
                                break;
3090
                        }
3091
                        thr = threadbuckets[still];
1,044✔
3092
                        for ( k = still+1; k < numthreadbuckets; k++ )
5,742✔
3093
                                threadbuckets[k-1] = threadbuckets[k];
4,698✔
3094
                        threadbuckets[numthreadbuckets-1] = thr;
1,044✔
3095
                        goto DoBucket;
1,044✔
3096
                }
3097
NextBucket:;
4,332✔
3098
        }
3099
/*
3100
        Now the stage one load balancing.
3101
        If the load has been readjusted we have again filled buckets.
3102
        In that case we jump back in the loop.
3103

3104
        Tricky point: when do the workers see the new value of AT.LoadBalancing?
3105
        It should activate the locks on thr->busy
3106
*/
3107
        if ( AC.ThreadBalancing ) {
45,648✔
3108
                for ( id = 1; id <= numberofworkers; id++ ) {
212,930✔
3109
                        AB[id]->T.LoadBalancing = 1;
167,282✔
3110
                }
3111
                if ( LoadReadjusted() ) goto Finalize;
45,648✔
3112
                for ( id = 1; id <= numberofworkers; id++ ) {
17,328✔
3113
                        AB[id]->T.LoadBalancing = 0;
12,996✔
3114
                }
3115
        }
3116
        if ( AC.ThreadBalancing ) {
4,332✔
3117
/*
3118
                The AS.Balancing flag should have Generator look for
3119
                free workers and apply the "buro" method.
3120

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

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

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

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

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

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

3486
int PutToMaster(PHEAD WORD *term)
7,851,160✔
3487
{
3488
        int i,j,nexti,ret = 0;
7,851,160✔
3489
        WORD *t, *fill, *top, zero = 0;
7,851,160✔
3490
        if ( term == 0 ) { /* Mark the end of the expression */
7,851,160✔
3491
                t = &zero; j = 1;
3492
        }
3493
        else {
3494
                t = term; ret = j = *term;
7,833,990✔
3495
                if ( j == 0 ) { j = 1; } /* Just in case there is a spurious end */
7,833,990✔
3496
        }
3497
        i = AT.SB.FillBlock;          /* The block we are working at */
7,851,160✔
3498
        fill = AT.SB.MasterFill[i];     /* Where we are filling */
7,851,160✔
3499
        top = AT.SB.MasterStop[i];      /* End of the block */
7,851,160✔
3500
        while ( j > 0 ) {
15,702,420✔
3501
                while ( j > 0 && fill < top ) {
195,531,900✔
3502
                        *fill++ = *t++; j--;
187,680,300✔
3503
                }
3504
                if ( j > 0 ) {
7,851,240✔
3505
/*
3506
                        We reached the end of the block.
3507
                        Get the next block and release this block.
3508
                        The order is important. This is why there should be at least
3509
                        4 blocks or deadlocks can occur.
3510
*/
3511
                        nexti = i+1;
82✔
3512
                        if ( nexti > AT.SB.MasterNumBlocks ) {
82✔
3513
                                nexti = 1;
11✔
3514
                        }
3515
                        LOCK(AT.SB.MasterBlockLock[nexti]);
82✔
3516
                        UNLOCK(AT.SB.MasterBlockLock[i]);
82✔
3517
                        AT.SB.MasterFill[i] = AT.SB.MasterStart[i];
82✔
3518
                        AT.SB.FillBlock = i = nexti;
82✔
3519
                        fill = AT.SB.MasterStart[i];
82✔
3520
                        top = AT.SB.MasterStop[i];
82✔
3521
                }
3522
        }
3523
        AT.SB.MasterFill[i] = fill;
7,851,160✔
3524
        return(ret);
7,851,160✔
3525
}
3526

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

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

3542
int
3543
SortBotOut(PHEAD WORD *term)
5,179,820✔
3544
{
3545
        WORD im;
5,179,820✔
3546

3547
        if ( AT.identity != 0 ) return(PutToMaster(BHEAD term));
5,179,820✔
3548

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

3567
#endif
3568

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

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

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

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

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

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

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

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

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

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

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

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

4169
        return(0);
2,146✔
4170
}
4171

4172
#endif
4173

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

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

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

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

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

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

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

4684
#endif
4685

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

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

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

4708
        if ( SortBlocksInitialized ) return(0);
574✔
4709
        SortBlocksInitialized = 1;
574✔
4710
        if ( numworkers == 0 ) return(0);
574✔
4711

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

4771
/*
4772
          #] IniSortBlocks : 
4773
          #[ UpdateSortBlocks :
4774
*/
4775
 
4776
/**
4777
 *        A version of IniSortBlocks which only updates the pointers in the master's
4778
 *        buffer, to be used after reallocation of that buffer.
4779
 */
4780
int UpdateSortBlocks(int numworkers)
8✔
4781
{
4782
        ALLPRIVATES *B;
8✔
4783
        SORTING *S;
8✔
4784
        LONG totalsize, workersize, blocksize, numberofterms;
8✔
4785
        int maxter, id, j;
8✔
4786
        int numberofblocks = NUMBEROFBLOCKSINSORT, numparts;
8✔
4787
        WORD *w;
8✔
4788

4789
        if ( numworkers == 0 ) return(0);
8✔
4790

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

4840
/*
4841
          #] UpdateSortBlocks : 
4842
          #[ DefineSortBotTree :
4843
*/
4844
 
4845
#ifdef WITHSORTBOTS
4846

4847
/**
4848
 *        To be used in a sortbot merge. It initializes the whole sortbot
4849
 *        system by telling the sortbot which threads provide their input.
4850
 */
4851

4852
void DefineSortBotTree(VOID)
574✔
4853
{
4854
        ALLPRIVATES *B;
574✔
4855
        int n, i, from;
574✔
4856
        if ( numberofworkers <= 2 ) return;
574✔
4857
        n = numberofworkers*2-2;
285✔
4858
        for ( i = numberofworkers+1, from = 1; i <= n; i++ ) {
855✔
4859
                B = AB[i];
570✔
4860
                AT.SortBotIn1 = from++;
570✔
4861
                AT.SortBotIn2 = from++;
570✔
4862
        }
4863
        B = AB[0];
285✔
4864
        AT.SortBotIn1 = from++;
285✔
4865
        AT.SortBotIn2 = from++;
285✔
4866
}
4867

4868
#endif
4869

4870
/*
4871
          #] DefineSortBotTree : 
4872
          #[ GetTerm2 :
4873

4874
        Routine does a GetTerm but only when a bracket index is involved and
4875
        only from brackets that have been judged not suitable for treatment
4876
        as complete brackets by a single worker. Whether or not a bracket should
4877
        be treated by a single worker is decided by TreatIndexEntry
4878
*/
4879

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

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

5019
/*
5020
          #] TreatIndexEntry : 
5021
          #[ SetHideFiles :
5022
*/
5023

5024
void SetHideFiles(VOID) {
30✔
5025
        int i;
30✔
5026
        ALLPRIVATES *B, *B0 = AB[0];
30✔
5027
        for ( i = 1; i <= numberofworkers; i++ ) {
120✔
5028
                B = AB[i];
90✔
5029
                AR.hidefile->handle = AR0.hidefile->handle;
90✔
5030
                if ( AR.hidefile->handle < 0 ) {
90✔
5031
                        AR.hidefile->PObuffer = AR0.hidefile->PObuffer;
90✔
5032
                        AR.hidefile->POstop = AR0.hidefile->POstop;
90✔
5033
                        AR.hidefile->POfill = AR0.hidefile->POfill;
90✔
5034
                        AR.hidefile->POfull = AR0.hidefile->POfull;
90✔
5035
                        AR.hidefile->POsize = AR0.hidefile->POsize;
90✔
5036
                        AR.hidefile->POposition = AR0.hidefile->POposition;
90✔
5037
                        AR.hidefile->filesize = AR0.hidefile->filesize;
90✔
5038
                }
5039
                else {
5040
                        AR.hidefile->PObuffer = AR.hidefile->wPObuffer;
×
5041
                        AR.hidefile->POstop = AR.hidefile->wPOstop;
×
5042
                        AR.hidefile->POfill = AR.hidefile->wPOfill;
×
5043
                        AR.hidefile->POfull = AR.hidefile->wPOfull;
×
5044
                        AR.hidefile->POsize = AR.hidefile->wPOsize;
×
5045
                        PUTZERO(AR.hidefile->POposition);
×
5046
                }
5047
        }
5048
}
30✔
5049

5050
/*
5051
          #] SetHideFiles : 
5052
          #[ IniFbufs :
5053
*/
5054

5055
void IniFbufs(VOID)
574✔
5056
{
5057
        int i;
574✔
5058
        for ( i = 0; i < AM.totalnumberofthreads; i++ ) {
2,858✔
5059
                IniFbuffer(AB[i]->T.fbufnum);
2,284✔
5060
        }
5061
}
574✔
5062

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

5068
void SetMods(VOID)
2✔
5069
{
5070
        ALLPRIVATES *B;
2✔
5071
        int i, n, j;
2✔
5072
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
10✔
5073
                B = AB[j];
8✔
5074
                AN.ncmod = AC.ncmod;
8✔
5075
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
8✔
5076
                n = ABS(AN.ncmod);
8✔
5077
                AN.cmod = (UWORD *)Malloc1(sizeof(WORD)*n,"AN.cmod");
8✔
5078
                for ( i = 0; i < n; i++ ) AN.cmod[i] = AC.cmod[i];
16✔
5079
        }
5080
}
2✔
5081

5082
/*
5083
          #] SetMods : 
5084
          #[ UnSetMods :
5085
*/
5086

5087
void UnSetMods(VOID)
2✔
5088
{
5089
        ALLPRIVATES *B;
2✔
5090
        int j;
2✔
5091
        for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
10✔
5092
                B = AB[j];
8✔
5093
                if ( AN.cmod != 0 ) M_free(AN.cmod,"AN.cmod");
8✔
5094
                AN.cmod = 0;
8✔
5095
        }
5096
}
2✔
5097

5098
/*
5099
          #] UnSetMods : 
5100
          #[ find_Horner_MCTS_expand_tree_threaded :
5101
*/
5102
 
5103
void find_Horner_MCTS_expand_tree_threaded(VOID) {
55✔
5104
        int id;
55✔
5105
        while (( id = GetAvailableThread() ) < 0)
85✔
5106
                MasterWait();        
30✔
5107
        WakeupThread(id,MCTSEXPANDTREE);
55✔
5108
}
55✔
5109

5110
/*
5111
          #] find_Horner_MCTS_expand_tree_threaded : 
5112
          #[ optimize_expression_given_Horner_threaded :
5113
*/
5114
 
5115
extern void optimize_expression_given_Horner_threaded(VOID) {
30✔
5116
        int id;
30✔
5117
        while (( id = GetAvailableThread() ) < 0)
30✔
5118
                MasterWait();        
×
5119
        WakeupThread(id,OPTIMIZEEXPRESSION);
30✔
5120
}
30✔
5121

5122
/*
5123
          #] optimize_expression_given_Horner_threaded : 
5124
*/
5125

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

© 2026 Coveralls, Inc