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

vermaseren / form / 11293612887

11 Oct 2024 01:52PM UTC coverage: 49.986% (+0.02%) from 49.968%
11293612887

Pull #526

github

web-flow
Merge 8495db7be into 4fc8e4047
Pull Request #526: RFC: better debugging

39 of 68 new or added lines in 2 files covered. (57.35%)

3 existing lines in 2 files now uncovered.

41423 of 82869 relevant lines covered (49.99%)

874620.04 hits per line

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

84.09
/sources/parallel.c
1
/** @file parallel.c
2
 *
3
 *  Message passing library independent functions of parform
4
 *
5
 *  This file contains functions needed for the parallel version of form3
6
 *  these functions need no real link to the message passing libraries, they
7
 *  only need some interface dependent preprocessor definitions (check
8
 *  parallel.h). So there still need two different objectfiles to be compiled
9
 *  for mpi and pvm!
10
 */
11
/* #[ License : */
12
/*
13
 *   Copyright (C) 1984-2023 J.A.M. Vermaseren
14
 *   When using this file you are requested to refer to the publication
15
 *   J.A.M.Vermaseren "New features of FORM" math-ph/0010025
16
 *   This is considered a matter of courtesy as the development was paid
17
 *   for by FOM the Dutch physics granting agency and we would like to
18
 *   be able to track its scientific use to convince FOM of its value
19
 *   for the community.
20
 *
21
 *   This file is part of FORM.
22
 *
23
 *   FORM is free software: you can redistribute it and/or modify it under the
24
 *   terms of the GNU General Public License as published by the Free Software
25
 *   Foundation, either version 3 of the License, or (at your option) any later
26
 *   version.
27
 *
28
 *   FORM is distributed in the hope that it will be useful, but WITHOUT ANY
29
 *   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30
 *   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
31
 *   details.
32
 *
33
 *   You should have received a copy of the GNU General Public License along
34
 *   with FORM.  If not, see <http://www.gnu.org/licenses/>.
35
 */
36
/* #] License : */ 
37
/*
38
          #[ includes :
39
*/
40
#include "form3.h"
41
#include "vector.h"
42

43
/*
44
#define PF_DEBUG_BCAST_LONG
45
#define PF_DEBUG_BCAST_BUF
46
#define PF_DEBUG_BCAST_PREDOLLAR
47
#define PF_DEBUG_BCAST_RHSEXPR
48
#define PF_DEBUG_BCAST_DOLLAR
49
#define PF_DEBUG_BCAST_PREVAR
50
#define PF_DEBUG_BCAST_CBUF
51
#define PF_DEBUG_BCAST_EXPRFLAGS
52
#define PF_DEBUG_REDUCE_DOLLAR
53
*/
54

55
/* mpi.c */
56
LONG PF_RealTime(int);
57
int PF_LibInit(int*, char***);
58
int PF_LibTerminate(int);
59
int PF_Probe(int*);
60
int PF_RecvWbuf(WORD*,LONG*,int*);
61
int PF_IRecvRbuf(PF_BUFFER*,int,int);
62
int PF_WaitRbuf(PF_BUFFER *,int,LONG *);
63
int PF_RawSend(int dest, void *buf, LONG l, int tag);
64
LONG PF_RawRecv(int *src,void *buf,LONG thesize,int *tag);
65
int PF_RawProbe(int *src, int *tag, int *bytesize);
66

67
/* Private functions */
68

69
static int PF_WaitAllSlaves(void);
70

71
static void PF_PackRedefinedPreVars(void);
72
static void PF_UnpackRedefinedPreVars(void);
73

74
static int PF_Wait4MasterIP(int tag);
75
static int PF_DoOneExpr(void);
76
static int PF_ReadMaster(void);/*reads directly to its scratch!*/
77
static int PF_Slave2MasterIP(int src);/*both master and slave*/
78
static int PF_Master2SlaveIP(int dest, EXPRESSIONS e);
79
static int PF_WalkThrough(WORD *t, LONG l, LONG chunk, LONG *count);
80
static int PF_SendChunkIP(FILEHANDLE *curfile,  POSITION *position, int to, LONG thesize);
81
static int PF_RecvChunkIP(FILEHANDLE *curfile, int from, LONG thesize);
82

83
static void PF_ReceiveErrorMessage(int src, int tag);
84
static void PF_CatchErrorMessages(int *src, int *tag);
85
static void PF_CatchErrorMessagesForAll(void);
86
static int PF_ProbeWithCatchingErrorMessages(int *src);
87

88
/* Variables */
89

90
PARALLELVARS PF;
91
#ifdef MPI2
92
 WORD *PF_shared_buff;
93
#endif
94

95
static LONG     PF_goutterms;  /* (master) Total out terms at PF_EndSort(), used in PF_Statistics(). */
96
static POSITION PF_exprsize;   /* (master) The size of the expression at PF_EndSort(), used in PF_Processor(). */
97

98
/*
99
        This will work well only under Linux, see
100
                #ifdef PF_WITH_SCHED_YIELD
101
        below in PF_WaitAllSlaves().
102
*/
103
#ifdef PF_WITH_SCHED_YIELD
104
 #include <sched.h>
105
#endif
106

107
#ifdef PF_WITHLOG
108
 #define PRINTFBUF(TEXT,TERM,SIZE)  { UBYTE lbuf[24]; if(PF.log){ WORD iii;\
109
  NumToStr(lbuf,AC.CModule); \
110
  fprintf(stderr,"[%d|%s] %s : ",PF.me,lbuf,(char*)TEXT);\
111
  if(TERM){ fprintf(stderr,"[%d] ",(int)(*TERM));\
112
    if((SIZE)<500 && (SIZE)>0) for(iii=1;iii<(SIZE);iii++)\
113
      fprintf(stderr,"%d ",TERM[iii]); }\
114
  fprintf(stderr,"\n");\
115
  fflush(stderr); } }
116
#else
117
 #define PRINTFBUF(TEXT,TERM,SIZE) {}
118
#endif
119

120
/**
121
 * Swaps the variables \a x and \a y. If sizeof(x) != sizeof(y) then a compilation error
122
 * will occur. A set of memcpy calls with constant sizes is expected to be inlined by the optimisation.
123
 */
124
#define SWAP(x, y) \
125
        do { \
126
                char swap_tmp__[sizeof(x) == sizeof(y) ? (int)sizeof(x) : -1]; \
127
                memcpy(swap_tmp__, &y, sizeof(x)); \
128
                memcpy(&y, &x, sizeof(x)); \
129
                memcpy(&x, swap_tmp__, sizeof(x)); \
130
        } while (0)
131

132
/**
133
 * Packs a LONG value \a n to a WORD buffer \a p.
134
 */
135
#define PACK_LONG(p, n) \
136
        do { \
137
                *(p)++ = (UWORD)((ULONG)(n) & (ULONG)WORDMASK); \
138
                *(p)++ = (UWORD)(((ULONG)(n) >> BITSINWORD) & (ULONG)WORDMASK); \
139
        } while (0)
140

141
/**
142
 * Unpacks a LONG value \a n from a WORD buffer \a p.
143
 */
144
#define UNPACK_LONG(p, n) \
145
        do { \
146
                (n) = (LONG)((((ULONG)(p)[1] & (ULONG)WORDMASK) << BITSINWORD) | ((ULONG)(p)[0] & (ULONG)WORDMASK)); \
147
                (p) += 2; \
148
        } while (0)
149

150
/**
151
 * A simple check for unrecoverable errors.
152
 */
153
#define CHECK(condition) _CHECK(condition, __FILE__, __LINE__)
154
#define _CHECK(condition, file, line) __CHECK(condition, file, line)
155
#define __CHECK(condition, file, line) \
156
        do { \
157
                if ( !(condition) ) { \
158
                        Error0("Fatal error at " file ":" #line); \
159
                        Terminate(-1); \
160
                } \
161
        } while (0)
162

163
/*
164
 * For debugging.
165
 */
166
#define DBGOUT(lv1, lv2, a) do { if ( lv1 >= lv2 ) { printf a; fflush(stdout); } } while (0)
167

168
/* (AN.ninterms of master) == max(AN.ninterms of slaves) == sum(PF_linterms of slaves) at EndSort(). */
169
#define DBGOUT_NINTERMS(lv, a)
170
/* #define DBGOUT_NINTERMS(lv, a) DBGOUT(1, lv, a) */
171

172
/*
173
          #] includes : 
174
          #[ statistics :
175
                 #[ variables : (should be part of a struct?)
176
*/
177
static LONG PF_linterms;     /* local interms on this proces: PF_Proces */
178
#define PF_STATS_SIZE 5
179
static LONG **PF_stats = NULL;/* space for collecting statistics of all procs */
180
static LONG PF_laststat;     /* last realtime when statistics were printed */
181
static LONG PF_statsinterval;/* timeinterval for printing statistics */
182
/*
183
                 #] variables : 
184
                 #[ PF_Statistics :
185
*/
186

187
/**
188
 * Prints statistics every PF_statinterval seconds.
189
 * For \a proc = 0 it prints final statistics for EndSort().
190
 *
191
 * @param  stats  the pointer to an array: LONG stats[proc][5] = {cpu,space,in,gen,left}.
192
 * @param  proc   the source process number.
193
 * @return        0 if OK, nonzero on error.
194
 */
195
static int PF_Statistics(LONG **stats, int proc)
9,970✔
196
{
197
        GETIDENTITY
198
        LONG real, cpu;
9,970✔
199
        WORD rpart, cpart;
9,970✔
200
        int i, j;
9,970✔
201

202
        if ( AT.SS == AM.S0 && PF.me == MASTER ) {
9,970✔
203
                real = PF_RealTime(PF_TIME); rpart = (WORD)(real%100); real /= 100;
9,965✔
204

205
                if ( PF_stats == NULL ) {
9,965✔
206
                        PF_stats = (LONG**)Malloc1(PF.numtasks*sizeof(LONG*),"PF_stats 1");
219✔
207
                        for ( i = 0; i < PF.numtasks; i++ ) {
1,095✔
208
                                PF_stats[i] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"PF_stats 2");
876✔
209
                                for ( j = 0; j < PF_STATS_SIZE; j++ ) PF_stats[i][j] = 0;
5,256✔
210
                        }
211
                }
212
                if ( proc > 0 ) for ( i = 0; i < PF_STATS_SIZE; i++ ) PF_stats[proc][i] = stats[0][i];
57,413✔
213

214
                if ( real >= PF_laststat + PF_statsinterval || proc == 0 ) {
9,965✔
215
                        LONG sum[PF_STATS_SIZE];
216

217
                        for ( i = 0; i < PF_STATS_SIZE; i++ ) sum[i] = 0;
12,342✔
218
                        sum[0] = cpu = TimeCPU(1);
2,057✔
219
                        cpart = (WORD)(cpu%1000);
2,057✔
220
                        cpu /= 1000;
2,057✔
221
                        cpart /= 10;
2,057✔
222
                        if ( AC.OldParallelStats ) MesPrint("");
2,057✔
223
                        if ( proc > 0 && AC.StatsFlag && AC.OldParallelStats ) {
2,057✔
224
                                MesPrint("proc          CPU         in        gen       left       byte");
×
225
                                MesPrint("%3d  : %7l.%2i %10l",0,cpu,cpart,AN.ninterms);
×
226
                        }
227
                        else if ( AC.StatsFlag && AC.OldParallelStats ) {
2,057✔
228
                                MesPrint("proc          CPU         in        gen       out        byte");
×
229
                                MesPrint("%3d  : %7l.%2i %10l %10l %10l",0,cpu,cpart,AN.ninterms,0,PF_goutterms);
×
230
                        }
231

232
                        for ( i = 1; i < PF.numtasks; i++ ) {
8,228✔
233
                                cpart = (WORD)(PF_stats[i][0]%1000);
6,171✔
234
                                cpu = PF_stats[i][0] / 1000;
6,171✔
235
                                cpart /= 10;
6,171✔
236
                                if ( AC.StatsFlag && AC.OldParallelStats )
6,171✔
237
                                        MesPrint("%3d  : %7l.%2i %10l %10l %10l",i,cpu,cpart,
×
238
                                                        PF_stats[i][2],PF_stats[i][3],PF_stats[i][4]);
239
                                for ( j = 0; j < PF_STATS_SIZE; j++ ) sum[j] += PF_stats[i][j];
37,026✔
240
                        }
241
                        cpart = (WORD)(sum[0]%1000);
2,057✔
242
                        cpu = sum[0] / 1000;
2,057✔
243
                        cpart /= 10;
2,057✔
244
                        if ( AC.StatsFlag && AC.OldParallelStats ) {
2,057✔
245
                                MesPrint("Sum  = %7l.%2i %10l %10l %10l",cpu,cpart,sum[2],sum[3],sum[4]);
×
246
                                MesPrint("Real = %7l.%2i %20s (%l) %16s",
×
247
                                                real,rpart,AC.Commercial,AC.CModule,EXPRNAME(AR.CurExpr));
×
248
                                MesPrint("");
×
249
                        }
250
                        PF_laststat = real;
2,057✔
251
                }
252
        }
253
        return(0);
9,970✔
254
}
255
/*
256
                 #] PF_Statistics : 
257
          #] statistics : 
258
          #[ sort.c :
259
                 #[ sort variables :
260
*/
261

262
/**
263
 * A node for the tree of losers in the final sorting on the master.
264
 */
265
typedef struct NoDe {
266
        struct NoDe *left;
267
        struct NoDe *rght;
268
        int lloser;
269
        int rloser;
270
        int lsrc;
271
        int rsrc;
272
} NODE;
273

274
/*
275
        should/could be put in one struct
276
*/
277
static  NODE *PF_root;                        /* root of tree of losers */
278
static  WORD PF_loser;                        /* this is the last loser */
279
static  WORD **PF_term;                        /* these point to the active terms */
280
static  WORD **PF_newcpos;                /* new coeffs of merged terms */
281
static  WORD *PF_newclen;                /* length of new coefficients */
282

283
/*
284
        preliminary: could also write somewhere else?
285
*/
286

287
static  WORD *PF_WorkSpace;                /* used in PF_EndSort() */
288
static  UWORD *PF_ScratchSpace;        /* used in PF_GetLoser() */
289

290
/*
291
                 #] sort variables : 
292
                 #[ PF_AllocBuf :
293
*/
294

295
/**
296
 * Allocates one PF_BUFFER struct with \a nbuf cyclic buffers of size \a bsize.
297
 * For the first \a free buffers there is no space allocated.
298
 * For example, if \a free == 1 then for the first (index 0) buffer there is
299
 * no space allocated(!!!) (one can reuse existing space for it) and
300
 * actually buff[0], stop[0], fill[0] and full[0] in the returned
301
 * PF_BUFFER struct are undefined.
302
 *
303
 * @param  nbufs  the number of cyclic buffers for PF_BUFFER struct.
304
 * @param  bsize  the memory allocation size in bytes for each buffer.
305
 * @param  free   the number of the buffers without the memory allocation.
306
 * @return        the pointer to the PF_BUFFER struct if succeeded. NULL if failed.
307
 *
308
 * @todo Maybe this should be really hidden in the send/recv routines and pvm/mpi
309
 *       files, it is only complicated because of nonblocking send/receives!
310
 */
311
static PF_BUFFER *PF_AllocBuf(int nbufs, LONG bsize, WORD free)
1,752✔
312
{
313
        PF_BUFFER *buf;
1,752✔
314
        UBYTE *p, *stop;
1,752✔
315
        LONG allocsize;
1,752✔
316
        int i;
1,752✔
317

318
        allocsize =
1,752✔
319
                (LONG)(sizeof(PF_BUFFER) + 4*nbufs*sizeof(WORD*) + (nbufs-free)*bsize);
1,752✔
320

321
        allocsize +=
1,752✔
322
                (LONG)( nbufs * (  2 * sizeof(MPI_Status)
1,752✔
323
                                 +     sizeof(MPI_Request)
324
                                 +     sizeof(MPI_Datatype)
325
                                )  );
326
        allocsize += (LONG)( nbufs * 3 * sizeof(int) );
1,752✔
327

328
        if ( ( buf = (PF_BUFFER*)Malloc1(allocsize,"PF_AllocBuf") ) == NULL ) return(NULL);
1,752✔
329

330
        p = ((UBYTE *)buf) + sizeof(PF_BUFFER);
1,752✔
331
        stop = ((UBYTE *)buf) + allocsize;
1,752✔
332

333
        buf->numbufs = nbufs;
1,752✔
334
        buf->active = 0;
1,752✔
335

336
        buf->buff    = (WORD**)p;                  p += buf->numbufs*sizeof(WORD*);
1,752✔
337
        buf->fill    = (WORD**)p;                  p += buf->numbufs*sizeof(WORD*);
1,752✔
338
        buf->full    = (WORD**)p;                  p += buf->numbufs*sizeof(WORD*);
1,752✔
339
        buf->stop    = (WORD**)p;                  p += buf->numbufs*sizeof(WORD*);
1,752✔
340
        buf->status  = (MPI_Status *)p;          p += buf->numbufs*sizeof(MPI_Status);
1,752✔
341
        buf->retstat = (MPI_Status *)p;          p += buf->numbufs*sizeof(MPI_Status);
1,752✔
342
        buf->request = (MPI_Request *)p;  p += buf->numbufs*sizeof(MPI_Request);
1,752✔
343
        buf->type    = (MPI_Datatype *)p; p += buf->numbufs*sizeof(MPI_Datatype);
1,752✔
344
        buf->index   = (int *)p;                  p += buf->numbufs*sizeof(int);
1,752✔
345

346
        for ( i = 0; i < buf->numbufs; i++ ) buf->request[i] = MPI_REQUEST_NULL;
5,475✔
347
        buf->tag     = (int *)p;                  p += buf->numbufs*sizeof(int);
1,752✔
348
        buf->from    = (int *)p;                  p += buf->numbufs*sizeof(int);
1,752✔
349
/*
350
                and finally the real bufferspace
351
*/
352
        for ( i = free; i < buf->numbufs; i++ ) {
3,066✔
353
                buf->buff[i] = (WORD*)p; p += bsize;
1,314✔
354
                buf->stop[i] = (WORD*)p;
1,314✔
355
                buf->fill[i] = buf->full[i] = buf->buff[i];
1,314✔
356
        }
357
        if ( p != stop ) {
1,752✔
358
                MesPrint("Error in PF_AllocBuf p = %x stop = %x\n",p,stop);
×
359
                return(NULL);
×
360
        }
361
        return(buf);
362
}
363

364
/*
365
                 #] PF_AllocBuf : 
366
                 #[ PF_InitTree :
367
*/
368

369
/**
370
 * Initializes the sorting tree on the master.
371
 * It allocates bufferspace (if necessary) for
372
 *   \li  pointers to terms in the tree and their coefficients
373
 *   \li  the cyclic receive buffers for nonblocking receives (PF.rbufs)
374
 *   \li  the nodes of the actual tree
375
 *
376
 * and initializes these with (hopefully) correct values.
377
 *
378
 * @return  the number of nodes in the merge tree if succeeded. -1 if failed.
379
*/
380
static int PF_InitTree(void)
2,057✔
381
{
382
        GETIDENTITY
383
        PF_BUFFER **rbuf = PF.rbufs;
2,057✔
384
        UBYTE *p, *stop;
2,057✔
385
        int numrbufs,numtasks = PF.numtasks;
2,057✔
386
        int i, j, src, numnodes;
2,057✔
387
        int numslaves = numtasks - 1;
2,057✔
388
        LONG size;
2,057✔
389
/*
390
                 #[ the buffers : for the new coefficients and the terms
391
                    we need one for each slave
392
*/
393
        if ( PF_term == NULL ) {
2,057✔
394
                size =  2*numtasks*sizeof(WORD*) + sizeof(WORD)*
219✔
395
                        ( numtasks*(1 + AM.MaxTal) + (AM.MaxTer/sizeof(WORD)+1) + 2*(AM.MaxTal+2));
219✔
396

397
                PF_term = (WORD **)Malloc1(size,"PF_term");
219✔
398
                stop = ((UBYTE*)PF_term) + size;
219✔
399
                p = ((UBYTE*)PF_term) + numtasks*sizeof(WORD*);
219✔
400

401
                PF_newcpos = (WORD **)p;  p += sizeof(WORD*) * numtasks;
219✔
402
                PF_newclen =  (WORD *)p;  p += sizeof(WORD)  * numtasks;
219✔
403
                for ( i = 0; i < numtasks; i++ ) {
1,095✔
404
                        PF_newcpos[i] = (WORD *)p; p += sizeof(WORD)*AM.MaxTal;
876✔
405
                        PF_newclen[i] = 0;
876✔
406
                }
407
                PF_WorkSpace = (WORD *)p;    p += AM.MaxTer+sizeof(WORD);
219✔
408
                PF_ScratchSpace = (UWORD*)p; p += 2*(AM.MaxTal+2)*sizeof(UWORD);
219✔
409

410
                if ( p != stop ) { MesPrint("error in PF_InitTree"); return(-1); }
219✔
411
        }
412
/*
413
                 #] the buffers : 
414
                 #[ the receive buffers :
415
*/
416
        numrbufs = PF.numrbufs;
2,057✔
417
/*
418
                this is the size we have in the combined sortbufs for one slave
419
*/
420
        size = (AT.SS->sTop2 - AT.SS->lBuffer - 1)/(PF.numtasks - 1);
2,057✔
421

422
        if ( rbuf == NULL ) {
2,057✔
423
                if ( ( rbuf = (PF_BUFFER**)Malloc1(numtasks*sizeof(PF_BUFFER*), "Master: rbufs") ) == NULL ) return(-1);
219✔
424
                if ( (rbuf[0] = PF_AllocBuf(1,0,1) ) == NULL ) return(-1);
219✔
425
                for ( i = 1; i < numtasks; i++ ) {
876✔
426
                        if (!(rbuf[i] = PF_AllocBuf(numrbufs,sizeof(WORD)*size,1))) return(-1);
657✔
427
                }
428
        }
429
        rbuf[0]->buff[0] = AT.SS->lBuffer;
2,057✔
430
        rbuf[0]->full[0] = rbuf[0]->fill[0] = rbuf[0]->buff[0];
2,057✔
431
        rbuf[0]->stop[0] = rbuf[1]->buff[0] = rbuf[0]->buff[0] + 1;
2,057✔
432
        rbuf[1]->full[0] = rbuf[1]->fill[0] = rbuf[1]->buff[0];
2,057✔
433
        for ( i = 2; i < numtasks; i++ ) {
6,171✔
434
                rbuf[i-1]->stop[0] = rbuf[i]->buff[0] = rbuf[i-1]->buff[0] + size;
4,114✔
435
                rbuf[i]->full[0] = rbuf[i]->fill[0] = rbuf[i]->buff[0];
4,114✔
436
        }
437
        rbuf[numtasks-1]->stop[0] = rbuf[numtasks-1]->buff[0] + size;
2,057✔
438

439
        for ( i = 1; i < numtasks; i++ ) {
8,228✔
440
                for ( j = 0; j < rbuf[i]->numbufs; j++ ) {
18,513✔
441
                        rbuf[i]->full[j] = rbuf[i]->fill[j] = rbuf[i]->buff[j] + AM.MaxTer/sizeof(WORD) + 2;
12,342✔
442
                }
443
                PF_term[i] = rbuf[i]->fill[rbuf[i]->active];
6,171✔
444
                *PF_term[i] = 0;
6,171✔
445
                PF_IRecvRbuf(rbuf[i],rbuf[i]->active,i);
6,171✔
446
        }
447
        rbuf[0]->active = 0;
2,057✔
448
        PF_term[0] = rbuf[0]->buff[0];
2,057✔
449
        PF_term[0][0] = 0;  /* PF_term[0] is used for a zero term. */
2,057✔
450
        PF.rbufs = rbuf;
2,057✔
451
/*
452
                 #] the receive buffers : 
453
                 #[ the actual tree :
454

455
         calculate number of nodes in mergetree and allocate space for them
456
*/
457
        if ( numslaves < 3 ) numnodes = 1;
2,057✔
458
        else {
459
                numnodes = 2;
460
                while ( numnodes < numslaves ) numnodes *= 2;
4,114✔
461
                numnodes -= 1;
2,057✔
462
        }
463

464
        if ( PF_root == NULL )
2,057✔
465
        if ( ( PF_root = (NODE*)Malloc1(sizeof(NODE)*numnodes,"nodes in mergetree") ) == NULL )
219✔
466
                return(-1);
467
/*
468
                then initialize all the nodes
469
*/
470
        src = 1;
471
        for ( i = 0; i < numnodes; i++ ) {
8,228✔
472
                if ( 2*(i+1) <= numnodes ) {
6,171✔
473
                        PF_root[i].left = &(PF_root[2*(i+1)-1]);
2,057✔
474
                        PF_root[i].lsrc = 0;
2,057✔
475
                }
476
                else {
477
                        PF_root[i].left = 0;
4,114✔
478
                        if ( src < numtasks ) PF_root[i].lsrc = src++;
4,114✔
479
                        else                  PF_root[i].lsrc = 0;
×
480
                }
481
                PF_root[i].lloser = 0;
6,171✔
482
        }
483
        for ( i = 0; i < numnodes; i++ ) {
8,228✔
484
                if ( 2*(i+1)+1 <= numnodes ) {
6,171✔
485
                        PF_root[i].rght = &(PF_root[2*(i+1)]);
2,057✔
486
                        PF_root[i].rsrc = 0;
2,057✔
487
                }
488
                else {
489
                        PF_root[i].rght = 0;
4,114✔
490
                        if (src<numtasks) PF_root[i].rsrc = src++;
4,114✔
491
                        else              PF_root[i].rsrc = 0;
2,057✔
492
                }
493
                PF_root[i].rloser = 0;
6,171✔
494
        }
495
/*
496
                 #] the actual tree : 
497
*/
498
        return(numnodes);
499
}
500

501
/*
502
                 #] PF_InitTree : 
503
                 #[ PF_PutIn :
504
*/
505

506
/**
507
 * Replaces PutIn() on the master process and is used in PF_GetLoser().
508
 * It puts in the next term from slaveprocess \a src into the tree of losers
509
 * on the master and is a lot like GetTerm(). The main problems are:
510
 * buffering and decompression.
511
 *
512
 * If \a src == 0, it returns the zero term (PF_term[0]).
513
 *
514
 * If \a src != 0, it receives terms from another machine.
515
 * They are stored in the large sortbuffer which is divided into buff[i]
516
 * in the PF.rbufs[src], if PF.numrbufs > 1.
517
 *
518
 * @param  src  the source process.
519
 * @return      the next term.
520
 *
521
 * @remark  PF_term[0][0] == 0 (see InitTree()), so PF_term[0] can be used to be
522
 *          the returnvalue for a zero term (== no more terms).
523
 */
524
static WORD *PF_PutIn(int src)
2,122,630✔
525
{
526
        int tag;
2,122,630✔
527
        WORD im, r;
2,122,630✔
528
        WORD *m1, *m2;
2,122,630✔
529
        LONG size;
2,122,630✔
530
        PF_BUFFER *rbuf = PF.rbufs[src];
2,122,630✔
531
        int a = rbuf->active;
2,122,630✔
532
        int next = a+1 >= rbuf->numbufs ? 0 : a+1 ;
2,122,630✔
533
        WORD *lastterm = PF_term[src];
2,122,630✔
534
        WORD *term = rbuf->fill[a];
2,122,630✔
535

536
        if ( src <= 0 ) return(PF_term[0]);
2,122,630✔
537

538
        if ( rbuf->full[a] == rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2 ) {
2,120,570✔
539
/*
540
                        very first term from this src
541
*/
542
                tag = PF_WaitRbuf(rbuf,a,&size);
6,171✔
543
                rbuf->full[a] += size;
6,171✔
544
                if ( tag == PF_ENDBUFFER_MSGTAG ) *rbuf->full[a]++ = 0;
6,171✔
545
                else if ( rbuf->numbufs > 1 ) {
×
546
/*
547
                                post a nonblock. recv. for the next buffer
548
*/
549
                        rbuf->full[next] = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 2;
×
550
                        size = (LONG)(rbuf->stop[next] - rbuf->full[next]);
×
551
                        PF_IRecvRbuf(rbuf,next,src);
×
552
                }
553
        }
554
        if ( *term == 0 && term != rbuf->full[a] ) return(PF_term[0]);
2,120,570✔
555
/*
556
                exception is for rare cases when the terms fitted exactly into buffer
557
*/
558
        if ( term + *term > rbuf->full[a] || term + 1 >= rbuf->full[a] ) {
2,114,400✔
559
newterms:
×
560
                m1 = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 1;
×
561
                if ( *term < 0 || term == rbuf->full[a] ) {
×
562
/*
563
                        copy term and lastterm to the new buffer, so that they end at m1
564
*/
565
                        m2 = rbuf->full[a] - 1;
×
566
                        while ( m2 >= term ) *m1-- = *m2--;
×
567
                        rbuf->fill[next] = term = m1 + 1;
×
568
                        m2 = lastterm + *lastterm - 1;
×
569
                        while ( m2 >= lastterm ) *m1-- = *m2--;
×
570
                        lastterm = m1 + 1;
×
571
                }
572
                else {
573
/*
574
                        copy beginning of term to the next buffer so that it ends at m1
575
*/
576
                        m2 = rbuf->full[a] - 1;
×
577
                        while ( m2 >= term ) *m1-- = *m2--;
×
578
                        rbuf->fill[next] = term = m1 + 1;
×
579
                }
580
                if ( rbuf->numbufs == 1 ) {
×
581
                        rbuf->full[a] = rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2;
×
582
                        size = (LONG)(rbuf->stop[a] - rbuf->full[a]);
×
583
                        PF_IRecvRbuf(rbuf,a,src);
×
584
                }
585
/*
586
                        wait for new terms in the next buffer
587
*/
588
                rbuf->full[next] = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 2;
×
589
                tag = PF_WaitRbuf(rbuf,next,&size);
×
590
                rbuf->full[next] += size;
×
591
                if ( tag == PF_ENDBUFFER_MSGTAG ) {
×
592
                        *rbuf->full[next]++ = 0;
×
593
                }
594
                else if ( rbuf->numbufs > 1 ) {
×
595
/*
596
                        post a nonblock. recv. for active buffer, it is not needed anymore
597
*/
598
                        rbuf->full[a] = rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2;
×
599
                        size = (LONG)(rbuf->stop[a] - rbuf->full[a]);
×
600
                        PF_IRecvRbuf(rbuf,a,src);
×
601
                }
602
/*
603
                        now safely make next buffer active
604
*/
605
                a = rbuf->active = next;
×
606
        }
607

608
        if ( *term < 0 ) {
2,114,400✔
609
/*
610
                        We need to decompress the term
611
*/
612
                im = *term;
79,248✔
613
                r = term[1] - im + 1;
79,248✔
614
                m1 = term + 2;
79,248✔
615
                m2 = lastterm - im + 1;
79,248✔
616
                while ( ++im <= 0 ) *--m1 = *--m2;
1,062,340✔
617
                *--m1 = r;
79,248✔
618
                rbuf->fill[a] = term = m1;
79,248✔
619
                if ( term + *term > rbuf->full[a] ) goto newterms;
79,248✔
620
        }
621
        rbuf->fill[a] += *term;
2,114,400✔
622
        return(term);
2,114,400✔
623
}
624

625
/*
626
                 #] PF_PutIn : 
627
                 #[ PF_GetLoser :
628
*/
629

630
/**
631
 * Finds the 'smallest' of all the PF_terms. Take also care of changing
632
 * coefficients and cancelling terms. When the coefficient changes, the new is
633
 * sitting in the array PF_newcpos, the length of the new coefficient in
634
 * PF_newclen. The original term will be untouched until it is copied to the
635
 * output buffer!
636
 *
637
 * Calling PF_GetLoser() with argument node will return the loser of the
638
 * subtree under node when the next term of the stream # PF_loser
639
 * (the last "loserstream") is filled into the tree.
640
 * PF_loser == 0 means we are just starting and should fill new terms into
641
 * all the leaves of the tree.
642
 *
643
 * @param  n  the node.
644
 * @return    the loser of the subtree under the node n.
645
 *            0 indicates there are no more terms.
646
 *            -1 indicates an error.
647
 */
648
static int PF_GetLoser(NODE *n)
4,229,700✔
649
{
650
        GETIDENTITY
651
        WORD comp;
4,229,700✔
652

653
        if ( PF_loser == 0 ) {
4,229,700✔
654
/*
655
                        this is for the right initialization of the tree only
656
*/
657
                if ( n->left ) n->lloser = PF_GetLoser(n->left);
6,171✔
658
                else {
659
                        n->lloser = n->lsrc;
4,114✔
660
                        if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0) n->lloser = 0;
4,114✔
661
                }
662
                PF_loser = 0;
6,171✔
663
                if ( n->rght ) n->rloser = PF_GetLoser(n->rght);
6,171✔
664
                else{
665
                        n->rloser = n->rsrc;
4,114✔
666
                        if ( *(PF_term[n->rsrc] = PF_PutIn(n->rsrc)) == 0 ) n->rloser = 0;
4,114✔
667
                }
668
                PF_loser = 0;
6,171✔
669
        }
670
        else if ( PF_loser == n->lloser ) {
4,223,520✔
671
                if ( n->left ) n->lloser = PF_GetLoser(n->left);
4,208,800✔
672
                else {
673
                        n->lloser = n->lsrc;
2,107,740✔
674
                        if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0 ) n->lloser = 0;
2,107,740✔
675
                }
676
        }
677
        else if ( PF_loser == n->rloser ) {
14,726✔
678
newright:
14,726✔
679
                if ( n->rght ) n->rloser = PF_GetLoser(n->rght);
16,543✔
680
                else {
681
                        n->rloser = n->rsrc;
5,793✔
682
                        if ( *(PF_term[n->rsrc] = PF_PutIn(n->rsrc)) == 0 ) n->rloser = 0;
5,793✔
683
                }
684
        }
685
        if ( n->lloser > 0 && n->rloser > 0 ) {
4,231,510✔
686
                comp = CompareTerms(BHEAD PF_term[n->lloser],PF_term[n->rloser],(WORD)0);
12,917✔
687
                if ( comp > 0 )     return(n->lloser);
12,917✔
688
                else if (comp < 0 ) return(n->rloser);
5,163✔
689
                else {
690
/*
691
                 #[ terms are equal :
692
*/
693
                        WORD *lcpos, *rcpos;
1,817✔
694
                        UWORD *newcpos;
1,817✔
695
                        WORD lclen, rclen, newclen, newnlen;
1,817✔
696
                        SORTING *S = AT.SS;
1,817✔
697

698
                        if ( S->PolyWise ) {
1,817✔
699
/*
700
                        #[ Here we work with PolyFun :
701
*/
702
                                WORD *tt1, *w;
516✔
703
                                WORD r1,r2;
516✔
704
                                WORD *ml = PF_term[n->lloser];
516✔
705
                                WORD *mr = PF_term[n->rloser];
516✔
706

707
                                if ( ( r1 = (int)*PF_term[n->lloser] ) <= 0 ) r1 = 20;
516✔
708
                                if ( ( r2 = (int)*PF_term[n->rloser] ) <= 0 ) r2 = 20;
516✔
709
                                tt1 = ml;
516✔
710
                                ml += S->PolyWise;
516✔
711
                                mr += S->PolyWise;
516✔
712
                                if ( S->PolyFlag == 2 ) {
516✔
713
                                        w = poly_ratfun_add(BHEAD ml,mr);
514✔
714
                                        if ( *tt1 + w[1] - ml[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
514✔
715
                                                MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
716
                                                Terminate(-1);
×
717
                                        }
718
                                        AT.WorkPointer = w;
514✔
719
                                }
720
                                else {
721
                                        w = AT.WorkPointer;
2✔
722
                                        if ( w + ml[1] + mr[1] > AT.WorkTop ) {
2✔
723
                                                MesPrint("A WorkSpace of %10l is too small",AM.WorkSize);
×
724
                                                Terminate(-1);
×
725
                                        }
726
                                        AddArgs(BHEAD ml,mr,w);
2✔
727
                                }
728
                                r1 = w[1];
516✔
729
                                if ( r1 <= FUNHEAD || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) ) {
516✔
730
                                        goto cancelled;
490✔
731
                                }
732
                                if ( r1 == ml[1] ) {
26✔
733
                                        NCOPY(ml,w,r1);
478✔
734
                                }
735
                                else if ( r1 < ml[1] ) {
23✔
736
                                        r2 = ml[1] - r1;
15✔
737
                                        mr = w + r1;
15✔
738
                                        ml += ml[1];
15✔
739
                                        while ( --r1 >= 0 ) *--ml = *--mr;
85,666✔
740
                                        mr = ml - r2;
15✔
741
                                        r1 = S->PolyWise;
15✔
742
                                        while ( --r1 >= 0 ) *--ml = *--mr;
180✔
743
                                        *ml -= r2;
15✔
744
                                        PF_term[n->lloser] = ml;
15✔
745
                                }
746
                                else {
747
                                        r2 = r1 - ml[1];
8✔
748
                                        if ( r2 > 2*AM.MaxTal )
8✔
749
                                                MesPrint("warning: new term in polyfun is large");
×
750
                                        mr = tt1 - r2;
8✔
751
                                        r1 = S->PolyWise;
8✔
752
                                        ml = tt1;
8✔
753
                                        *ml += r2;
8✔
754
                                        PF_term[n->lloser] = mr;
8✔
755
                                        NCOPY(mr,ml,r1);
96✔
756
                                        r1 = w[1];
8✔
757
                                        NCOPY(mr,w,r1);
2,508✔
758
                                }
759
                                PF_newclen[n->rloser] = 0;
26✔
760
                                PF_loser = n->rloser;
26✔
761
                                goto newright;
1,817✔
762
/*
763
                        #] Here we work with PolyFun : 
764
*/
765
                        }
766
                        if ( ( lclen = PF_newclen[n->lloser] ) != 0 ) lcpos = PF_newcpos[n->lloser];
1,301✔
767
                        else {
768
                                lcpos = PF_term[n->lloser];
1,281✔
769
                                lclen = *(lcpos += *lcpos - 1);
1,281✔
770
                                lcpos -= ABS(lclen) - 1;
1,281✔
771
                        }
772
                        if ( ( rclen = PF_newclen[n->rloser] ) != 0 ) rcpos = PF_newcpos[n->rloser];
1,301✔
773
                        else {
774
                                rcpos = PF_term[n->rloser];
1,301✔
775
                                rclen = *(rcpos += *rcpos - 1);
1,301✔
776
                                rcpos -= ABS(rclen) -1;
1,301✔
777
                        }
778
                        lclen = ( (lclen > 0) ? (lclen-1) : (lclen+1) ) >> 1;
1,301✔
779
                        rclen = ( (rclen > 0) ? (rclen-1) : (rclen+1) ) >> 1;
1,301✔
780
                        newcpos = PF_ScratchSpace;
1,301✔
781
                        if ( AddRat(BHEAD (UWORD *)lcpos,lclen,(UWORD *)rcpos,rclen,newcpos,&newnlen) ) return(-1);
1,301✔
782
                        if ( AN.ncmod != 0 ) {
1,301✔
783
                                if ( ( AC.modmode & POSNEG ) != 0 ) {
×
784
                                        NormalModulus(newcpos,&newnlen);
×
785
                                }
786
                                if ( BigLong(newcpos,newnlen,(UWORD *)AC.cmod,ABS(AN.ncmod)) >=0 ) {
×
787
                                        WORD ii;
×
788
                                        SubPLon(newcpos,newnlen,(UWORD *)AC.cmod,ABS(AN.ncmod),newcpos,&newnlen);
×
789
                                        newcpos[newnlen] = 1;
×
790
                                        for ( ii = 1; ii < newnlen; ii++ ) newcpos[newnlen+ii] = 0;
×
791
                                }
792
                        }
793
                        if ( newnlen == 0 ) {
1,301✔
794
/*
795
                                        terms cancel, get loser of left subtree and then of right subtree
796
*/
797
cancelled:
1,135✔
798
                                PF_loser = n->lloser;
1,625✔
799
                                PF_newclen[n->lloser] = 0;
1,625✔
800
                                if ( n->left ) n->lloser = PF_GetLoser(n->left);
1,625✔
801
                                else {
802
                                        n->lloser = n->lsrc;
866✔
803
                                        if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0 ) n->lloser = 0;
866✔
804
                                }
805
                                PF_loser = n->rloser;
1,625✔
806
                                PF_newclen[n->rloser] = 0;
1,625✔
807
                                goto newright;
1,625✔
808
                        }
809
                        else {
810
/*
811
                                        keep the left term and get the loser of right subtree
812
*/
813
                                newnlen *= 2;
166✔
814
                                newclen = ( newnlen > 0 ) ? ( newnlen + 1 ) : ( newnlen - 1 );
166✔
815
                                if ( newnlen < 0 ) newnlen = -newnlen;
166✔
816
                                PF_newclen[n->lloser] = newclen;
166✔
817
                                lcpos = PF_newcpos[n->lloser];
166✔
818
                                if ( newclen < 0 ) newclen = -newclen;
166✔
819
                                while ( newclen-- ) *lcpos++ = *newcpos++;
680✔
820
                                PF_loser = n->rloser;
166✔
821
                                PF_newclen[n->rloser] = 0;
166✔
822
                                goto newright;
166✔
823
                        }
824
/*
825
                 #] terms are equal : 
826
*/
827
                }
828
        }
829
        if (n->lloser > 0) return(n->lloser);
4,218,600✔
830
        if (n->rloser > 0) return(n->rloser);
17,551✔
831
        return(0);
832
}
833
/*
834
                 #] PF_GetLoser : 
835
                 #[ PF_EndSort :
836
*/
837

838
/**
839
 * Finishes a master sorting with collecting terms from slaves.
840
 * Called by EndSort().
841
 *
842
 * If this is not the masterprocess, just initialize the sendbuffers and
843
 * return 0, else PF_EndSort() sends the rest of the terms in the sendbuffer
844
 * to the next slave and a dummy message to all slaves with tag
845
 * PF_ENDSORT_MSGTAG. Then it receives the sorted terms, sorts them using a
846
 * recursive 'tree of losers' (PF_GetLoser()) and writes them to the
847
 * outputfile.
848
 *
849
 * @return   1  if the sorting on the master was done.
850
 *           0  if EndSort() still must perform a regular sorting because it is not
851
 *              at the ground level or not on the master or in the sequential mode
852
 *              or in the InParallel mode.
853
 *          -1  if an error occurred.
854
 *
855
 * @remark  The slaves will send the sorted terms back to the master in the regular
856
 *          sorting (after the initialization of the send buffer in PF_EndSort()).
857
 *          See PutOut() and FlushOut().
858
 *
859
 * @remark  This function has been changed such that when it returns 1,
860
 *          AM.S0->TermsLeft is set correctly. But AM.S0->GenTerms is not set:
861
 *          it will be set after collecting the statistics from the slaves
862
 *          at the end of PF_Processor(). (TU 30 Jun 2011)
863
 */
864
int PF_EndSort(void)
829,407✔
865
{
866
        GETIDENTITY
867
        FILEHANDLE *fout = AR.outfile;
829,407✔
868
        PF_BUFFER *sbuf=PF.sbuf;
829,407✔
869
        SORTING *S = AT.SS;
829,407✔
870
        WORD *outterm,*pp;
829,407✔
871
        LONG size, noutterms;
829,407✔
872
        POSITION position, oldposition;
829,407✔
873
        WORD i,cc;
829,407✔
874
        int oldgzipCompress;
829,407✔
875

876
        if ( AT.SS != AT.S0 || !PF.parallel ) return 0;
829,407✔
877

878
        if ( PF.me != MASTER ) {
8,228✔
879
/*
880
                 #[ the slaves have to initialize their sendbuffer :
881

882
                this is a slave and it's PObuffer should be the minimum of the
883
                sortiosize on the master and the POsize of our file.
884
                First save the original PObuffer and POstop of the outfile
885
*/
886
                size = (S->sTop2 - S->lBuffer - 1)/(PF.numtasks - 1);
6,171✔
887
                size -= (AM.MaxTer/sizeof(WORD) + 2);
6,171✔
888
                if ( fout->POsize < (LONG)(size*sizeof(WORD)) ) size = fout->POsize/sizeof(WORD);
6,171✔
889
                if ( sbuf == NULL ) {
6,171✔
890
                        if ( (sbuf = PF_AllocBuf(PF.numsbufs, size*sizeof(WORD), 1)) == NULL ) return -1;
657✔
891
                        sbuf->active = 0;
657✔
892
                        PF.sbuf = sbuf;
657✔
893
                }
894
                sbuf->buff[0] = fout->PObuffer;
6,171✔
895
                sbuf->stop[0] = fout->PObuffer+size;
6,171✔
896
                if ( sbuf->stop[0] > fout->POstop ) return -1;
6,171✔
897
                for ( i = 0; i < PF.numsbufs; i++ )
18,513✔
898
                        sbuf->fill[i] = sbuf->full[i] = sbuf->buff[i];
12,342✔
899

900
                fout->PObuffer = sbuf->buff[sbuf->active];
6,171✔
901
                fout->POstop = sbuf->stop[sbuf->active];
6,171✔
902
                fout->POsize = size*sizeof(WORD);
6,171✔
903
                fout->POfill = fout->POfull = fout->PObuffer;
6,171✔
904
/*
905
                 #] the slaves have to initialize their sendbuffer : 
906
*/
907
                return(0);
6,171✔
908
        }
909
/*
910
                this waits for all slaves to be ready to send terms back
911
*/
912
        PF_WaitAllSlaves(); /* Note, the returned value should be 0 on success. */
2,057✔
913
/*
914
                Now collect the terms of all slaves and merge them.
915
                PF_GetLoser gives the position of the smallest term, which is the real
916
                work. The smallest term needs to be copied to the outbuf: use PutOut.
917
*/
918
        PF_InitTree();
2,057✔
919
        if ( AR.PolyFun == 0 ) { S->PolyFlag = 0; }
2,057✔
920
        else if ( AR.PolyFunType == 1 ) { S->PolyFlag = 1; }
548✔
921
        else if ( AR.PolyFunType == 2 ) {
542✔
922
                if ( AR.PolyFunExp == 2
542✔
923
                  || AR.PolyFunExp == 3 ) S->PolyFlag = 1;
542✔
924
                else                      S->PolyFlag = 2;
523✔
925
        }
926
        *AR.CompressPointer = 0;
2,057✔
927
        SeekScratch(fout, &position);
2,057✔
928
        oldposition = position;
2,057✔
929
        oldgzipCompress = AR.gzipCompress;
2,057✔
930
        AR.gzipCompress = 0;
2,057✔
931

932
        noutterms = 0;
2,057✔
933

934
        while ( PF_loser >= 0 ) {
2,113,020✔
935
                if ( (PF_loser = PF_GetLoser(PF_root)) == 0 ) break;
2,113,020✔
936
                outterm = PF_term[PF_loser];
2,110,960✔
937
                noutterms++;
2,110,960✔
938

939
                if ( PF_newclen[PF_loser] != 0 ) {
2,110,960✔
940
/*
941
                        #[ this is only when new coeff was too long :
942
*/
943
                        outterm = PF_WorkSpace;
146✔
944
                        pp = PF_term[PF_loser];
146✔
945
                        cc = *pp;
146✔
946
                        while ( cc-- ) *outterm++ = *pp++;
1,989✔
947
                        outterm = (outterm[-1] > 0) ? outterm-outterm[-1] : outterm+outterm[-1];
146✔
948
                        if ( PF_newclen[PF_loser] > 0 ) cc =  (WORD)PF_newclen[PF_loser] - 1;
146✔
949
                        else                            cc = -(WORD)PF_newclen[PF_loser] - 1;
4✔
950
                        pp =  PF_newcpos[PF_loser];
146✔
951
                        while ( cc-- ) *outterm++ = *pp++;
446✔
952
                        *outterm++ = PF_newclen[PF_loser];
146✔
953
                        *PF_WorkSpace = outterm - PF_WorkSpace;
146✔
954
                        outterm = PF_WorkSpace;
146✔
955
                        *PF_newcpos[PF_loser] = 0;
146✔
956
                        PF_newclen[PF_loser] = 0;
146✔
957
/*
958
                        #] this is only when new coeff was too long : 
959
*/
960
                }
961
                PRINTFBUF("PF_EndSort to PutOut: ",outterm,*outterm);
2,110,960✔
962
                PutOut(BHEAD outterm,&position,fout,1);
2,110,960✔
963
        }
964
        if ( FlushOut(&position,fout,0) ) {
2,057✔
965
                AR.gzipCompress = oldgzipCompress;
×
966
                return(-1);
×
967
        }
968
        S->TermsLeft = PF_goutterms = noutterms;
2,057✔
969
        DIFPOS(PF_exprsize, position, oldposition);
2,057✔
970
        AR.gzipCompress = oldgzipCompress;
2,057✔
971
        return(1);
2,057✔
972
}
973

974
/*
975
                 #] PF_EndSort : 
976
          #] sort.c : 
977
          #[ proces.c :
978
                 #[ variables :
979
*/
980

981
static  WORD *PF_CurrentBracket;
982

983
/*
984
                 #] variables : 
985
                 #[ PF_GetTerm :
986
*/
987

988
/**
989
 * Replaces GetTerm() on the slaves, which get their terms from the master,
990
 * not the infile anymore, is nonblocking and buffered ...
991
 * use AR.infile->PObuffer as buffer. For the moment, don't care
992
 * about compression, since terms come uncompressed from master.
993
 *
994
 * To enable keep-brackets when AR.DeferFlag is set, we need to do some
995
 * preparation here:
996
 *   \li  copy the part outside brackets to current_bracket
997
 *   \li  skip term if part outside brackets is same as for last term
998
 *   \li  if POfill >= POfull receive new terms as usual
999
 *
1000
 * Different from GetTerm() we use an extra buffer for the part outside brackets:
1001
 * PF_CurrentBracket.
1002
 *
1003
 * @param[out]  term  the buffer to store the next term.
1004
 * @return            the length of the next term.
1005
 */
1006
static WORD PF_GetTerm(WORD *term)
24,994✔
1007
{
1008
        GETIDENTITY
1009
        FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
24,994✔
1010
        WORD i;
24,994✔
1011
        WORD *next, *np, *last, *lp = 0, *nextstop, *tp=term;
24,994✔
1012

1013
        /* Only on the slaves. */
1014

1015
        AN.deferskipped = 0;
24,994✔
1016
        if ( fi->POfill >= fi->POfull || fi->POfull == fi->PObuffer ) {
24,994✔
1017
ReceiveNew:
7,908✔
1018
          {
1019
/*
1020
                 #[ receive new terms from master :
1021
*/
1022
                int src = MASTER, tag;
7,908✔
1023
                int follow = 0;
7,908✔
1024
                LONG size,cpu,space = 0;
7,908✔
1025

1026
                if ( PF.log ) {
7,908✔
1027
                        fprintf(stderr,"[%d] Starting to send to Master\n",PF.me);
×
1028
                        fflush(stderr);
×
1029
                }
1030

1031
                cpu = TimeCPU(1);
7,908✔
1032
                PF_PreparePack();
7,908✔
1033
                PF_Pack(&cpu               ,1,PF_LONG);
7,908✔
1034
                PF_Pack(&space             ,1,PF_LONG);
7,908✔
1035
                PF_Pack(&PF_linterms       ,1,PF_LONG);
7,908✔
1036
                PF_Pack(&(AM.S0->GenTerms) ,1,PF_LONG);
7,908✔
1037
                PF_Pack(&(AM.S0->TermsLeft),1,PF_LONG);
7,908✔
1038
                PF_Pack(&follow            ,1,PF_INT );
7,908✔
1039

1040
                if ( PF.log ) {
7,908✔
1041
                        fprintf(stderr,"[%d] Now sending with tag = %d\n",PF.me,PF_READY_MSGTAG);
×
1042
                        fflush(stderr);
×
1043
                }
1044

1045
                PF_Send(MASTER, PF_READY_MSGTAG);
7,908✔
1046

1047
                if ( PF.log ) {
7,908✔
1048
                        fprintf(stderr,"[%d] returning from send\n",PF.me);
×
1049
                        fflush(stderr);
×
1050
                }
1051

1052
                size = fi->POstop - fi->PObuffer - 1;
7,908✔
1053
#ifdef AbsolutelyExtra
1054
                PF_Receive(MASTER,PF_ANY_MSGTAG,&src,&tag);
1055
#ifdef MPI2
1056
                if ( tag == PF_TERM_MSGTAG ) {
1057
                        PF_Unpack(&size, 1, PF_LONG);
1058
                        if ( PF_Put_target(src) == 0 ) {
1059
                                printf("PF_Put_target error ...\n");
1060
                        }
1061
                }
1062
                else {
1063
                        PF_RecvWbuf(fi->PObuffer,&size,&src);
1064
                }
1065
#else
1066
                PF_RecvWbuf(fi->PObuffer,&size,&src);
1067
#endif
1068
#endif
1069
                tag=PF_RecvWbuf(fi->PObuffer,&size,&src);
7,908✔
1070

1071
                fi->POfill = fi->PObuffer;
7,908✔
1072
                /* Get AN.ninterms which sits in the first 2 WORDs. */
1073
                {
1074
                        LONG ninterms;
7,908✔
1075
                        UNPACK_LONG(fi->POfill, ninterms);
7,908✔
1076
                        if ( fi->POfill < fi->POfull ) {
7,908✔
1077
                                DBGOUT_NINTERMS(2, ("PF.me=%d AN.ninterms=%d PF_linterms=%d ninterms=%d GET\n", (int)PF.me, (int)AN.ninterms, (int)PF_linterms, (int)ninterms));
1,737✔
1078
                                AN.ninterms = ninterms - 1;
1,737✔
1079
                        } else {
1080
                                DBGOUT_NINTERMS(2, ("PF.me=%d AN.ninterms=%d PF_linterms=%d ninterms=%d GETEND\n", (int)PF.me, (int)AN.ninterms, (int)PF_linterms, (int)ninterms));
7,908✔
1081
                        }
1082
                }
1083
                fi->POfull = fi->PObuffer + size;
7,908✔
1084
                if ( tag == PF_ENDSORT_MSGTAG ) *fi->POfull++ = 0;
7,908✔
1085
/*
1086
                 #] receive new terms from master : 
1087
*/
1088
          }
1089
          if ( PF_CurrentBracket ) *PF_CurrentBracket = 0;
7,908✔
1090
        }
1091
        if ( *fi->POfill == 0 ) {
24,994✔
1092
                fi->POfill = fi->POfull = fi->PObuffer;
6,171✔
1093
                *term = 0;
6,171✔
1094
                goto RegRet;
6,171✔
1095
        }
1096
        if ( AR.DeferFlag ) {
18,823✔
1097
                if ( !PF_CurrentBracket ) {
3✔
1098
/*
1099
                 #[ alloc space :
1100
*/
1101
                        PF_CurrentBracket =
6✔
1102
                                        (WORD*)Malloc1(AM.MaxTer,"PF_CurrentBracket");
3✔
1103
                        *PF_CurrentBracket = 0;
3✔
1104
/*
1105
                 #] alloc space : 
1106
*/
1107
                }
1108
                while ( *PF_CurrentBracket ) {  /* "for each term in the buffer" */
3✔
1109
/*
1110
                 #[ test : bracket & skip if it's equal to the last in PF_CurrentBracket
1111
*/
1112
                        next = fi->POfill;
×
1113
                        nextstop = next + *next; nextstop -= ABS(nextstop[-1]);
×
1114
                        next++;
×
1115
                        last = PF_CurrentBracket+1;
×
1116
                        while ( next < nextstop ) {
×
1117
/*
1118
                                        scan the next term and PF_CurrentBracket
1119
*/
1120
                                if ( *last == HAAKJE && *next == HAAKJE ) {
×
1121
/*
1122
                                        the part outside brackets is equal => skip this term
1123
*/
1124
                                        PRINTFBUF("PF_GetTerm skips",fi->POfill,*fi->POfill);
×
1125
                                        break;
×
1126
                                }
1127
/*
1128
                                        check if the current subterms are equal
1129
*/
1130
                                np = next; next += next[1];
×
1131
                                lp = last; last += last[1];
×
1132
                                while ( np < next ) if ( *lp++ != *np++ ) goto strip;
×
1133
                        }
1134
/*
1135
                                go on to next term
1136
*/
1137
                        fi->POfill += *fi->POfill;
×
1138
                        AN.deferskipped++;
×
1139
/*
1140
                                the usual checks
1141
*/
1142
                        if ( fi->POfill >= fi->POfull || fi->POfull == fi->PObuffer )
×
1143
                                goto ReceiveNew;
×
1144
                        if ( *fi->POfill == 0 ) {
×
1145
                                fi->POfill = fi->POfull = fi->PObuffer;
×
1146
                                *term = 0;
×
1147
                                goto RegRet;
×
1148
                        }
1149
/*
1150
                 #] test : 
1151
*/
1152
                }
1153
/*
1154
                 #[ copy :
1155

1156
                this term to CurrentBracket and the part outside of bracket
1157
                to WorkSpace at term
1158
*/
1159
strip:
3✔
1160
                next = fi->POfill;
3✔
1161
                nextstop = next + *next; nextstop -= ABS(nextstop[-1]);
3✔
1162
                next++;
3✔
1163
                tp++;
3✔
1164
                lp = PF_CurrentBracket + 1;
3✔
1165
                while ( next < nextstop ) {
6✔
1166
                        if ( *next == HAAKJE ) {
6✔
1167
                                fi->POfill += *fi->POfill;
3✔
1168
                                while ( next < fi->POfill ) *lp++ = *next++;
35✔
1169
                                *PF_CurrentBracket = lp - PF_CurrentBracket;
3✔
1170
                                *lp = 0;
3✔
1171
                                *tp++ = 1;
3✔
1172
                                *tp++ = 1;
3✔
1173
                                *tp++ = 3;
3✔
1174
                                *term = WORDDIF(tp,term);
3✔
1175
                                PRINTFBUF("PF_GetTerm new brack",PF_CurrentBracket,*PF_CurrentBracket);
3✔
1176
                                PRINTFBUF("PF_GetTerm POfill",fi->POfill,*fi->POfill);
3✔
1177
                                goto RegRet;
3✔
1178
                        }
1179
                        np = next; next += next[1];
3✔
1180
                        while ( np < next ) *tp++ = *lp++ = *np++;
37✔
1181
                }
1182
                tp = term;
1183
/*
1184
                 #] copy : 
1185
*/
1186
        }
1187

1188
        i = *fi->POfill;
18,820✔
1189
        while ( i-- ) *tp++ = *fi->POfill++;
5,383,890✔
1190
RegRet:
18,820✔
1191
        PRINTFBUF("PF_GetTerm returns",term,*term);
24,994✔
1192
        return(*term);
24,994✔
1193
}
1194

1195
/*
1196
                 #] PF_GetTerm : 
1197
                 #[ PF_Deferred :
1198
*/
1199

1200
/**
1201
 * Replaces Deferred() on the slaves.
1202
 *
1203
 * @param  term   the term that must be multiplied by the contents of
1204
 *                the current bracket.
1205
 * @param  level  the compiler level.
1206
 * @return        0 if OK, nonzero on error.
1207
 */
1208
WORD PF_Deferred(WORD *term, WORD level)
2,027,030✔
1209
{
1210
        GETIDENTITY
1211
        WORD *bra, *bstop;
2,027,030✔
1212
        WORD *tstart;
2,027,030✔
1213
        FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
2,027,030✔
1214
        WORD *next = fi->POfill;
2,027,030✔
1215
        WORD *termout = AT.WorkPointer;
2,027,030✔
1216
        WORD *oldwork = AT.WorkPointer;
2,027,030✔
1217

1218
        AT.WorkPointer = (WORD *)((UBYTE *)(AT.WorkPointer) + AM.MaxTer);
2,027,030✔
1219
        AR.DeferFlag = 0;
2,027,030✔
1220

1221
        PRINTFBUF("PF_Deferred (Term)   ",term,*term);
2,027,030✔
1222
        PRINTFBUF("PF_Deferred (Bracket)",PF_CurrentBracket,*PF_CurrentBracket);
2,027,030✔
1223

1224
        bra = bstop = PF_CurrentBracket;
2,027,030✔
1225
        if ( *bstop > 0 ) {
2,027,030✔
1226
                bstop += *bstop;
2,027,030✔
1227
                bstop -= ABS(bstop[-1]);
2,027,030✔
1228
        }
1229
        bra++;
2,027,030✔
1230
        while ( *bra != HAAKJE && bra < bstop ) bra += bra[1];
4,054,050✔
1231
        if ( bra >= bstop ) {        /* No deferred action! */
2,027,030✔
1232
                AT.WorkPointer = term + *term;
×
1233
                if ( Generator(BHEAD term,level) ) goto DefCall;
×
1234
                AR.DeferFlag = 1;
×
1235
                AT.WorkPointer = oldwork;
×
1236
                return(0);
×
1237
        }
1238
        bstop = bra;
2,027,030✔
1239
        tstart = bra + bra[1];
2,027,030✔
1240
        bra = PF_CurrentBracket;
2,027,030✔
1241
        tstart--;
2,027,030✔
1242
        *tstart = bra + *bra - tstart;
2,027,030✔
1243
        bra++;
2,027,030✔
1244
/*
1245
                Status of affairs:
1246
                First bracket content starts at tstart.
1247
                Next term starts at next.
1248
                The outside of the bracket runs from bra = PF_CurrentBracket to bstop.
1249
*/
1250
        for(;;) {
2,027,030✔
1251
                if ( InsertTerm(BHEAD term,0,AM.rbufnum,tstart,termout,0) < 0 ) {
2,027,030✔
1252
                        goto DefCall;
×
1253
                }
1254
/*
1255
                        call Generator with new composed term
1256
*/
1257
                AT.WorkPointer = termout + *termout;
2,027,030✔
1258
                if ( Generator(BHEAD termout,level) ) goto DefCall;
2,027,030✔
1259
                AT.WorkPointer = termout;
2,027,030✔
1260
                tstart = next + 1;
2,027,030✔
1261
                if ( tstart >= fi->POfull ) goto ThatsIt;
2,027,030✔
1262
                next += *next;
×
1263
/*
1264
                        compare with current bracket
1265
*/
1266
                while ( bra <= bstop ) {
×
1267
                        if ( *bra != *tstart ) goto ThatsIt;
×
1268
                        bra++; tstart++;
×
1269
                }
1270
/*
1271
                        now bra and tstart should both be a HAAKJE
1272
*/
1273
                bra--; tstart--;
×
1274
                if ( *bra != HAAKJE || *tstart != HAAKJE ) goto ThatsIt;
×
1275
                tstart += tstart[1];
×
1276
                tstart--;
×
1277
                *tstart = next - tstart;
×
1278
                bra = PF_CurrentBracket + 1;
×
1279
        }
1280

1281
ThatsIt:
2,027,030✔
1282
/*
1283
        AT.WorkPointer = oldwork;
1284
*/
1285
        AR.DeferFlag = 1;
2,027,030✔
1286
        return(0);
2,027,030✔
1287
DefCall:
×
1288
        MesCall("PF_Deferred");
×
1289
        SETERROR(-1);
×
1290
}
1291

1292
/*
1293
                 #] PF_Deferred : 
1294
                 #[ PF_Wait4Slave :
1295
*/
1296

1297
static LONG **PF_W4Sstats = 0;
1298

1299
/**
1300
 * Waits for the slave \a src to accept terms.
1301
 *
1302
 * @param  src  the slave for waiting (can be PF_ANY_SOURCE).
1303
 * @return      the idle slave.
1304
 */
1305
static int PF_Wait4Slave(int src)
7,908✔
1306
{
1307
        int j, tag, next;
7,908✔
1308

1309
        tag = PF_ANY_MSGTAG;
7,908✔
1310
        PF_CatchErrorMessages(&src, &tag);
7,908✔
1311
        PF_Receive(src, tag, &next, &tag);
7,908✔
1312

1313
        if ( tag != PF_READY_MSGTAG ) {
7,908✔
1314
                MesPrint("[%d] PF_Wait4Slave: received MSGTAG %d",(WORD)PF.me,(WORD)tag);
×
1315
                return(-1);
×
1316
        }
1317
        if ( PF_W4Sstats == 0 ) {
7,908✔
1318
                PF_W4Sstats = (LONG**)Malloc1(sizeof(LONG*),"");
218✔
1319
                PF_W4Sstats[0] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"");
218✔
1320
        }
1321
        PF_Unpack(PF_W4Sstats[0],PF_STATS_SIZE,PF_LONG);
7,908✔
1322
        PF_Statistics(PF_W4Sstats,next);
7,908✔
1323

1324
        PF_Unpack(&j,1,PF_INT);
7,908✔
1325

1326
        if ( j ) {
7,908✔
1327
/*
1328
                actions depending on rest of information in last message
1329
*/
1330
        }
7,908✔
1331
        return(next);
7,908✔
1332
}
1333

1334
/*
1335
                 #] PF_Wait4Slave : 
1336
                 #[ PF_Wait4SlaveIP :
1337
*/
1338
/*
1339
        array of expression numbers for PF_InParallel processor.
1340
        Each time the master sends expression "i" to the slave
1341
        "next" it sets partodoexr[next]=i:
1342
*/
1343
static WORD *partodoexr=NULL;
1344

1345
/**
1346
 * InParallel version of PF_Wait4Slave(). Returns tag as src.
1347
 *
1348
 * @param[in,out]  src  the slave for waiting (can be PF_ANY_SOURCE).
1349
 *                      As output, the tag value of the idle slave.
1350
 * @return              the idle slave.
1351
 */
1352
static int PF_Wait4SlaveIP(int *src)
4✔
1353
{
1354
        int j,tag,next;
4✔
1355

1356
        tag = PF_ANY_MSGTAG;
4✔
1357
        PF_CatchErrorMessages(src, &tag);
4✔
1358
        PF_Receive(*src, tag, &next, &tag);
4✔
1359
        *src=tag;
4✔
1360
        if ( PF_W4Sstats == 0 ) {
4✔
1361
                PF_W4Sstats = (LONG**)Malloc1(sizeof(LONG*),"");
1✔
1362
                PF_W4Sstats[0] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"");
1✔
1363
        }
1364

1365
        PF_Unpack(PF_W4Sstats[0],PF_STATS_SIZE,PF_LONG);
4✔
1366
        if ( tag == PF_DATA_MSGTAG )
4✔
1367
                AR.CurExpr = partodoexr[next];
1✔
1368
        PF_Statistics(PF_W4Sstats,next);
4✔
1369

1370
        PF_Unpack(&j,1,PF_INT);
4✔
1371

1372
        if ( j ) {
4✔
1373
        /* actions depending on rest of information in last message */
1374
        }
4✔
1375

1376
        return(next);
4✔
1377
}
1378
/*
1379
                 #] PF_Wait4SlaveIP : 
1380
                 #[ PF_WaitAllSlaves :
1381
*/
1382

1383
/**
1384
 * Waits until all slaves are ready to send terms back to the master.
1385
 * If some slave is not working, it sends PF_ENDSORT_MSGTAG and waits for the answer.
1386
 * Messages from slaves will be read only after all slaves are ready,
1387
 * further in caller function.
1388
 *
1389
 * @return  0 if OK, nonzero on error.
1390
 */
1391
static int PF_WaitAllSlaves(void)
2,058✔
1392
{
1393
        int i, readySlaves, tag, next = PF_ANY_SOURCE;
2,058✔
1394
        UBYTE *has_sent = 0;
2,058✔
1395

1396
        has_sent = (UBYTE*)Malloc1(sizeof(UBYTE)*(PF.numtasks + 1),"PF_WaitAllSlaves");
2,058✔
1397
        for ( i = 0; i < PF.numtasks; i++ ) has_sent[i] = 0;
12,348✔
1398

1399
        for ( readySlaves = 1; readySlaves < PF.numtasks; ) {
14,908,600✔
1400
                if ( next != PF_ANY_SOURCE) { /*Go to the next slave:*/
14,906,500✔
1401
                        do{ /*Note, here readySlaves<PF.numtasks, so this loop can't be infinite*/
44,008,000✔
1402
                                if ( ++next >= PF.numtasks ) next = 1;
44,008,000✔
1403
                        } while ( has_sent[next] == 1 );
44,008,000✔
1404
                }
1405
/*
1406
                        Here PF_ProbeWithCatchingErrorMessages() is BLOCKING function if next = PF_ANY_SOURCE:
1407
*/
1408
                tag = PF_ProbeWithCatchingErrorMessages(&next);
14,906,500✔
1409
/*
1410
                        Here next != PF_ANY_SOURCE
1411
*/
1412
                switch ( tag ) {
14,906,500✔
1413
                        case PF_BUFFER_MSGTAG:
6,171✔
1414
                        case PF_ENDBUFFER_MSGTAG:
1415
/*
1416
                                        Slaves are ready to send their results back
1417
*/
1418
                                if ( has_sent[next] == 0 ) {
6,171✔
1419
                                        has_sent[next] = 1;
6,171✔
1420
                                        readySlaves++;
6,171✔
1421
                                }
1422
                                else {  /*error?*/
1423
                                        fprintf(stderr,"ERROR next=%d tag=%d\n",next,tag);
×
1424
                                }
1425
/*
1426
                                        Note, we do NOT read results here! Messages from these slaves will be read
1427
                                        only after all slaves are ready, further in caller function
1428
*/
1429
                                break;
1430
                        case 0:
1431
/*
1432
                                        The slave is not ready. Just go to the next slave.
1433
                                        It may appear that there are no more ready slaves, and the master
1434
                                        will wait them in infinite loop. Stupid situation - the master can
1435
                                        receive buffers from ready slaves!
1436
*/
1437
#ifdef PF_WITH_SCHED_YIELD
1438
/*
1439
                                                Relinquish the processor:
1440
*/
1441
                                        sched_yield();
1442
#endif
1443
                                break;
1444
                        case PF_DATA_MSGTAG:
1✔
1445
                                tag=next;
1✔
1446
                                next=PF_Wait4SlaveIP(&tag);
1✔
1447
/*
1448
        tag must be == PF_DATA_MSGTAG!
1449
*/
1450
                                PF_Statistics(PF_stats,0);
1✔
1451
                                PF_Slave2MasterIP(next);
1✔
1452
                                PF_Master2SlaveIP(next,NULL);
1✔
1453
                                if ( has_sent[next] == 0 ) {
1✔
1454
                                        has_sent[next]=1;
1✔
1455
                                        readySlaves++;
1✔
1456
                                }else{
1457
                                        /*error?*/
1458
                                        fprintf(stderr,"ERROR next=%d tag=%d\n",next,tag);
×
1459
                                }/*if ( has_sent[next] == 0 )*/
1460
                                break;
1461
                        case PF_EMPTY_MSGTAG:
2✔
1462
                                tag=next;
2✔
1463
                                next=PF_Wait4SlaveIP(&tag);
2✔
1464
/*
1465
        tag must be == PF_EMPTY_MSGTAG!
1466
*/
1467
                                PF_Master2SlaveIP(next,NULL);
2✔
1468
                                if ( has_sent[next] == 0 ) {
2✔
1469
                                        has_sent[next]=1;
2✔
1470
                                        readySlaves++;
2✔
1471
                                }else{
1472
                                        /*error?*/
1473
                                        fprintf(stderr,"ERROR next=%d tag=%d\n",next,tag);
14,908,600✔
1474
                                }/*if ( has_sent[next] == 0 )*/
1475
                                break;
1476
                        case PF_READY_MSGTAG:
6,171✔
1477
/*
1478
                                        idle slave
1479
                                        May be only PF_READY_MSGTAG:
1480
*/
1481
                                next = PF_Wait4Slave(next);
6,171✔
1482
                                if ( next == -1 ) return(next); /*Cannot be!*/
6,171✔
1483
                                if ( has_sent[0] == 0 ) {  /*Send the last chunk to the slave*/
6,171✔
1484
                                        PF.sbuf->active = 0;
2,057✔
1485
                                        has_sent[0] = 1;
2,057✔
1486
                                }
1487
                                else {
1488
/*
1489
                                                Last chunk was sent, so just send to slave ENDSORT
1490
                                                AN.ninterms must be sent because the slave expects it:
1491
*/
1492
                                        PACK_LONG(PF.sbuf->fill[next], AN.ninterms);
4,114✔
1493
/*
1494
                                                This will tell to the slave that there are no more terms:
1495
*/
1496
                                        *(PF.sbuf->fill[next])++ = 0;
4,114✔
1497
                                        PF.sbuf->active = next;
4,114✔
1498
                                }
1499
/*
1500
                                        Send ENDSORT
1501
*/
1502
                                PF_ISendSbuf(next,PF_ENDSORT_MSGTAG);
6,171✔
1503
                                break;
6,171✔
1504
                        default:
×
1505
/*
1506
                                        Error?
1507
                                        Indicates the error. This will force exit from the main loop:
1508
*/
1509
                                MesPrint("!!!Unexpected MPI message src=%d tag=%d.", next, tag);
×
1510
                                readySlaves = PF.numtasks+1;
×
1511
                                break;
×
1512
                }
1513
        }
1514

1515
        if ( has_sent ) M_free(has_sent,"PF_WaitAllSlaves");
2,058✔
1516
/*
1517
                0 on success (exit from the main loop by loop condition), or -1 if fails
1518
                (exit from the main loop since readySlaves=PF.numtasks+1):
1519
*/
1520
        return(PF.numtasks-readySlaves);
2,058✔
1521
}
1522

1523
/*
1524
                 #] PF_WaitAllSlaves : 
1525
                 #[ PF_Processor :
1526
*/
1527

1528
/**
1529
 * Replaces parts of Processor() on the masters and slaves.
1530
 * On the master PF_Processor() is responsible for proper distribution of terms
1531
 * from the input file to the slaves.
1532
 * On the slaves it calls Generator() for all the terms that this process gets,
1533
 * but PF_GetTerm() gets terms from the master (not directly from infile).
1534
 *
1535
 * @param  e               The pointer to the current expression.
1536
 * @param  i               The index for the current expression.
1537
 * @param  LastExpression  The flag indicating whether it is the last expression.
1538
 * @return                 0 if OK, nonzero on error.
1539
 */
1540
int PF_Processor(EXPRESSIONS e, WORD i, WORD LastExpression)
8,332✔
1541
{
1542
        GETIDENTITY
1543
        WORD *term = AT.WorkPointer;
8,332✔
1544
        LONG dd = 0;
8,332✔
1545
        PF_BUFFER *sb = PF.sbuf;
8,332✔
1546
        WORD j, *s, next;
8,332✔
1547
        LONG size, cpu;
8,332✔
1548
        POSITION position;
8,332✔
1549
        int k, src, tag;
8,332✔
1550
        FILEHANDLE *oldoutfile = AR.outfile;
8,332✔
1551

1552
#ifdef MPI2
1553
        if ( PF_shared_buff == NULL ) {
1554
                if ( PF_SMWin_Init() == 0 ) {
1555
                        MesPrint("PF_SMWin_Init error");
1556
                        exit(-1);
1557
                }
1558
        }
1559
#endif
1560

1561
        if ( ( (WORD *)(((UBYTE *)(AT.WorkPointer)) + AM.MaxTer ) ) > AT.WorkTop ) return(MesWork());
8,332✔
1562

1563
        /* For redefine statements. */
1564
        if ( AC.numpfirstnum > 0 ) {
8,332✔
1565
                for ( j = 0; j < AC.numpfirstnum; j++ ) {
40✔
1566
                        AC.inputnumbers[j] = -1;
20✔
1567
                }
1568
        }
1569

1570
        if ( AC.mparallelflag != PARALLELFLAG ) return(0);
8,332✔
1571

1572
        if ( PF.me == MASTER ) {
8,228✔
1573
/*
1574
                 #[ Master:
1575
                        #[ write prototype to outfile:
1576
*/
1577
                WORD oldBracketOn = AR.BracketOn;
2,057✔
1578
                WORD *oldBrackBuf = AT.BrackBuf;
2,057✔
1579
                WORD oldbracketindexflag = AT.bracketindexflag;
2,057✔
1580

1581
                LONG maxinterms;     /* the maximum number of terms in the bucket */
2,057✔
1582
                int cmaxinterms;     /* a variable controling the transition of maxinterms */
2,057✔
1583
                LONG termsinbucket;  /* the number of filled terms in the bucket */
2,057✔
1584
                LONG ProcessBucketSize = AC.mProcessBucketSize;
2,057✔
1585

1586
                if ( PF.log && AC.CModule >= PF.log )
2,057✔
1587
                        MesPrint("[%d] working on expression %s in module %l",PF.me,EXPRNAME(i),AC.CModule);
×
1588
                if ( GetTerm(BHEAD term) <= 0 ) {
2,057✔
1589
                        MesPrint("[%d] Expression %d has problems in scratchfile",PF.me,i);
×
1590
                        return(-1);
×
1591
                }
1592
                term[3] = i;
2,057✔
1593
                if ( AR.outtohide ) {
2,057✔
1594
                        SeekScratch(AR.hidefile,&position);
1✔
1595
                        e->onfile = position;
1✔
1596
                        if ( PutOut(BHEAD term,&position,AR.hidefile,0) < 0 ) return(-1);
1✔
1597
                }
1598
                else {
1599
                        SeekScratch(AR.outfile,&position);
2,056✔
1600
                        e->onfile = position;
2,056✔
1601
                        if ( PutOut(BHEAD term,&position,AR.outfile,0) < 0 ) return(-1);
2,056✔
1602
                }
1603
                AR.DeferFlag = 0;  /* The master leave the brackets!!! */
2,057✔
1604
                AR.Eside = RHSIDE;
2,057✔
1605
                if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
2,057✔
1606
                        AR.BracketOn = 1;
23✔
1607
                        AT.BrackBuf = AM.BracketFactors;
23✔
1608
                        AT.bracketindexflag = 1;
23✔
1609
                }
1610
                if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
2,057✔
1611
/*
1612
                        #] write prototype to outfile: 
1613
                        #[ initialize sendbuffer if necessary:
1614

1615
                        the size of the sendbufs is:
1616
                        MIN(1/PF.numtasks*(AT.SS->sBufsize+AT.SS->lBufsize),AR.infile->POsize)
1617
                        No allocation for extra buffers necessary, just make sb->buf... point
1618
                        to the right places in the sortbuffers.
1619
*/
1620
                NewSort(BHEAD0);   /* we need AT.SS to be set for this!!! */
2,057✔
1621
                if ( sb == 0 || sb->buff[0] != AT.SS->lBuffer ) {
2,057✔
1622
                        size = (LONG)((AT.SS->sTop2 - AT.SS->lBuffer)/(PF.numtasks));
532✔
1623
                        if ( size > (LONG)(AR.infile->POsize/sizeof(WORD) - 1) )
532✔
1624
                                size = AR.infile->POsize/sizeof(WORD) - 1;
×
1625
                        if ( sb == 0 ) {
532✔
1626
                                if ( ( sb = PF_AllocBuf(PF.numtasks,size*sizeof(WORD),PF.numtasks) ) == NULL )
219✔
1627
                                        return(-1);
1628
                        }
1629
                        sb->buff[0] = AT.SS->lBuffer;
532✔
1630
                        sb->full[0] = sb->fill[0] = sb->buff[0];
532✔
1631
                        for ( j = 1; j < PF.numtasks; j++ ) {
2,128✔
1632
                                sb->stop[j-1] = sb->buff[j] = sb->buff[j-1] + size;
1,596✔
1633
                        }
1634
                        sb->stop[PF.numtasks-1] = sb->buff[PF.numtasks-1] + size;
532✔
1635
                        PF.sbuf = sb;
532✔
1636
                }
1637
                for ( j = 0; j < PF.numtasks; j++ ) {
10,285✔
1638
                        sb->full[j] = sb->fill[j] = sb->buff[j];
8,228✔
1639
                }
1640
/*
1641
                        #] initialize sendbuffer if necessary: 
1642
                        #[ loop for all terms in infile:
1643
*/
1644
                /*
1645
                 * The initial value of maxinterms is determined by the user given
1646
                 * ProcessBucketSize and the number of terms in the current expression.
1647
                 * We make the initial maxinterms smaller, so that we get the all
1648
                 * workers busy as soon as possible.
1649
                 */
1650
                maxinterms = ProcessBucketSize / 100;
2,057✔
1651
                if ( maxinterms > e->counter / (PF.numtasks - 1) / 4 )
2,057✔
1652
                        maxinterms = e->counter / (PF.numtasks - 1) / 4;
2,039✔
1653
                if ( maxinterms < 1 ) maxinterms = 1;
2,057✔
1654
                cmaxinterms = 0;
2,057✔
1655
                /*
1656
                 * Copy them always to sb->buff[0]. When that is full, wait for
1657
                 * the next slave to accept terms, exchange sb->buff[0] and
1658
                 * sb->buff[next], send sb->buff[next] to next slave and go on
1659
                 * filling the now empty sb->buff[0].
1660
                 */
1661
                AN.ninterms = 0;
2,057✔
1662
                termsinbucket = 0;
2,057✔
1663
                PACK_LONG(sb->fill[0], 1);
2,057✔
1664
                while ( GetTerm(BHEAD term) ) {
20,880✔
1665
                        AN.ninterms++; dd = AN.deferskipped;
18,823✔
1666
                        if ( AC.CollectFun && *term <= (LONG)(AM.MaxTer/(2*sizeof(WORD))) ) {
18,823✔
1667
                                if ( GetMoreTerms(term) < 0 ) {
83✔
1668
                                        LowerSortLevel(); return(-1);
×
1669
                                }
1670
                        }
1671
                        PRINTFBUF("PF_Processor gets",term,*term);
18,823✔
1672
                        if ( termsinbucket >= maxinterms || sb->fill[0] + *term >= sb->stop[0] ) {
18,823✔
1673
                                next = PF_Wait4Slave(PF_ANY_SOURCE);
1,737✔
1674

1675
                                sb->fill[next] = sb->fill[0];
1,737✔
1676
                                sb->full[next] = sb->full[0];
1,737✔
1677
                                SWAP(sb->stop[next], sb->stop[0]);
1,737✔
1678
                                SWAP(sb->buff[next], sb->buff[0]);
1,737✔
1679
                                sb->fill[0] = sb->full[0] = sb->buff[0];
1,737✔
1680
                                sb->active = next;
1,737✔
1681

1682
#ifdef MPI2
1683
                                if ( PF_Put_origin(next) == 0 ) {
1684
                                        printf("PF_Put_origin error...\n");
1685
                                }
1686
#else
1687
                                PF_ISendSbuf(next,PF_TERM_MSGTAG);
1,737✔
1688
#endif
1689
                                /* Initialize the next bucket. */
1690
                                termsinbucket = 0;
1,737✔
1691
                                PACK_LONG(sb->fill[0], AN.ninterms);
1,737✔
1692
                                /*
1693
                                 * For the "slow startup". We double maxinterms up to ProcessBucketSize
1694
                                 * after (hopefully) the all workers got some terms.
1695
                                 */
1696
                                if ( cmaxinterms >= PF.numtasks - 2 ) {
1,737✔
1697
                                        maxinterms *= 2;
795✔
1698
                                        if ( maxinterms >= ProcessBucketSize ) {
795✔
1699
                                                cmaxinterms = -1;
2✔
1700
                                                maxinterms = ProcessBucketSize;
2✔
1701
                                        }
1702
                                }
1703
                                else if ( cmaxinterms >= 0 ) {
942✔
1704
                                        cmaxinterms++;
891✔
1705
                                }
1706
                        }
1707
                        j = *(s = term);
18,823✔
1708
                        NCOPY(sb->fill[0], s, j);
5,383,960✔
1709
                        termsinbucket++;
18,823✔
1710
                }
1711
                /* NOTE: The last chunk will be sent to a slave at EndSort() => PF_EndSort()
1712
                 *       => PF_WaitAllSlaves(). */
1713
                AN.ninterms += dd;
2,057✔
1714
/*
1715
                        #] loop for all terms in infile: 
1716
                        #[ Clean up & EndSort:
1717
*/
1718
                if ( LastExpression ) {
2,057✔
1719
                        UpdateMaxSize();
411✔
1720
                        if ( AR.infile->handle >= 0 ) {
411✔
1721
                                CloseFile(AR.infile->handle);
×
1722
                                AR.infile->handle = -1;
×
1723
                                remove(AR.infile->name);
×
1724
                                PUTZERO(AR.infile->POposition);
×
1725
                        }
1726
                        AR.infile->POfill = AR.infile->POfull = AR.infile->PObuffer;
411✔
1727
                }
1728
                if ( AR.outtohide ) AR.outfile = AR.hidefile;
2,057✔
1729
                PF.parallel = 1;
2,057✔
1730
                if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) return(-1);
2,057✔
1731
                PF.parallel = 0;
2,057✔
1732
                if ( AR.outtohide ) {
2,057✔
1733
                        AR.outfile = oldoutfile;
1✔
1734
                        AR.hidefile->POfull = AR.hidefile->POfill;
1✔
1735
                }
1736
                UpdateMaxSize();
2,057✔
1737
                AR.BracketOn = oldBracketOn;
2,057✔
1738
                AT.BrackBuf = oldBrackBuf;
2,057✔
1739
                if ( ( e->vflags & TOBEFACTORED ) != 0 )
2,057✔
1740
                        poly_factorize_expression(e);
9✔
1741
                else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
2,048✔
1742
                 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
2,048✔
1743
                        poly_unfactorize_expression(e);
1✔
1744
                AT.bracketindexflag = oldbracketindexflag;
2,057✔
1745
                AR.GetFile = 0;
2,057✔
1746
                AR.outtohide = 0;
2,057✔
1747
                /*
1748
                 * NOTE: e->numdummies, e->vflags and AR.exprflags will be updated
1749
                 *       after gathering the information from all slaves.
1750
                 */
1751
/*
1752
                        #] Clean up & EndSort: 
1753
                        #[ Collect (stats,prepro,...):
1754
*/
1755
                DBGOUT_NINTERMS(1, ("PF.me=%d AN.ninterms=%d ENDSORT\n", (int)PF.me, (int)AN.ninterms));
2,057✔
1756
                PF_CatchErrorMessagesForAll();
2,057✔
1757
                e->numdummies = 0;
2,057✔
1758
                for ( k = 1; k < PF.numtasks; k++ ) {
8,228✔
1759
                        PF_LongSingleReceive(PF_ANY_SOURCE, PF_ENDSORT_MSGTAG, &src, &tag);
6,171✔
1760
                        PF_LongSingleUnpack(PF_stats[src], PF_STATS_SIZE, PF_LONG);
6,171✔
1761
                        {
1762
                                WORD numdummies, expchanged;
6,171✔
1763
                                PF_LongSingleUnpack(&numdummies, 1, PF_WORD);
6,171✔
1764
                                PF_LongSingleUnpack(&expchanged, 1, PF_WORD);
6,171✔
1765
                                if ( e->numdummies < numdummies ) e->numdummies = numdummies;
6,171✔
1766
                                AR.expchanged |= expchanged;
6,171✔
1767
                        }
1768
                        /* Now handle redefined preprocessor variables. */
1769
                        if ( AC.numpfirstnum > 0 ) PF_UnpackRedefinedPreVars();
6,171✔
1770
                }
1771
                if ( ! AC.OldParallelStats ) {
2,057✔
1772
                        /* Now we can calculate AT.SS->GenTerms from the statistics of the slaves. */
1773
                        LONG genterms = 0;
1774
                        for ( k = 1; k < PF.numtasks; k++ ) {
8,228✔
1775
                                genterms += PF_stats[k][3];
6,171✔
1776
                        }
1777
                        AT.SS->GenTerms = genterms;
2,057✔
1778
                        WriteStats(&PF_exprsize, STATSPOSTSORT, NOCHECKLOGTYPE);
2,057✔
1779
                        Expressions[AR.CurExpr].size = PF_exprsize;
2,057✔
1780
                }
1781
                PF_Statistics(PF_stats,0);
2,057✔
1782
/*
1783
                        #] Collect (stats,prepro,...): 
1784
                        #[ Update flags :
1785
*/
1786
                if ( AM.S0->TermsLeft ) e->vflags &= ~ISZERO;
2,057✔
1787
                else e->vflags |= ISZERO;
456✔
1788
                if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
2,057✔
1789
                if ( AM.S0->TermsLeft ) AR.expflags |= ISZERO;
2,057✔
1790
                if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;
2,057✔
1791
/*
1792
                        #] Update flags : 
1793
                 #] Master: 
1794
*/
1795
        }
1796
        else {
1797
/*
1798
                 #[ Slave :
1799
*/
1800
/*
1801
                        #[ Generator Loop & EndSort :
1802

1803
                        loop for all terms to get from master, call Generator for each of them
1804
                        then call EndSort and do cleanup (to be implemented)
1805
*/
1806
                WORD oldBracketOn = AR.BracketOn;
6,171✔
1807
                WORD *oldBrackBuf = AT.BrackBuf;
6,171✔
1808
                WORD oldbracketindexflag = AT.bracketindexflag;
6,171✔
1809

1810
                /* For redefine statements. */
1811
                if ( AC.numpfirstnum > 0 ) {
6,171✔
1812
                        for ( j = 0; j < AC.numpfirstnum; j++ ) {
24✔
1813
                                AC.inputnumbers[j] = -1;
12✔
1814
                        }
1815
                }
1816

1817
                SeekScratch(AR.outfile,&position);
6,171✔
1818
                e->onfile = position;
6,171✔
1819
                AR.DeferFlag = AC.ComDefer;
6,171✔
1820
                AR.Eside = RHSIDE;
6,171✔
1821
                if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
6,171✔
1822
                        AR.BracketOn = 1;
69✔
1823
                        AT.BrackBuf = AM.BracketFactors;
69✔
1824
                        AT.bracketindexflag = 1;
69✔
1825
                }
1826
                NewSort(BHEAD0);
6,171✔
1827
                AR.MaxDum = AM.IndDum;
6,171✔
1828
                AN.ninterms = 0;
6,171✔
1829
                PF_linterms = 0;
6,171✔
1830
                PF.parallel = 1;
6,171✔
1831
#ifdef MPI2
1832
                AR.infile->POfull = AR.infile->POfill = AR.infile->PObuffer = PF_shared_buff;
1833
#endif
1834
                {
1835
                        FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
6,171✔
1836
                        fi->POfull = fi->POfill = fi->PObuffer;
6,171✔
1837
                }
1838
                /* FIXME: AN.ninterms is still broken when AN.deferskipped is non-zero.
1839
                 *        It still needs some work, also in PF_GetTerm(). (TU 30 Aug 2011) */
1840
                while ( PF_GetTerm(term) ) {
24,994✔
1841
                        PF_linterms++; AN.ninterms++; dd = AN.deferskipped;
18,823✔
1842
                        AT.WorkPointer = term + *term;
18,823✔
1843
                        AN.RepPoint = AT.RepCount + 1;
18,823✔
1844
                        if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
18,823✔
1845
                                StoreTerm(BHEAD term);
×
1846
                                continue;
×
1847
                        }
1848
                        if ( AR.DeferFlag ) {
18,823✔
1849
                                AR.CurDum = AN.IndDum = Expressions[AR.CurExpr].numdummies + AM.IndDum;
3✔
1850
                        }
1851
                        else {
1852
                                AN.IndDum = AM.IndDum;
18,820✔
1853
                                AR.CurDum = ReNumber(BHEAD term);
18,820✔
1854
                        }
1855
                        if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
18,823✔
1856
                        if ( AN.ncmod ) {
18,823✔
1857
                                if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
1✔
1858
                                else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
1✔
1859
                        }
1860
                        else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
18,822✔
1861
                        if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
18,823✔
1862
                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
710✔
1863
                                PolyFunClean(BHEAD term);
710✔
1864
                        }
1865
                        if ( Generator(BHEAD term,0) ) {
18,823✔
1866
                                MesPrint("[%d] PF_Processor: Error in Generator",PF.me);
×
1867
                                LowerSortLevel(); return(-1);
×
1868
                        }
1869
                        PF_linterms += dd; AN.ninterms += dd;
18,823✔
1870
                }
1871
                PF_linterms += dd; AN.ninterms += dd;
6,171✔
1872
                {
1873
                        /*
1874
                         * EndSort() overrides AR.outfile->PObuffer etc. (See also PF_EndSort()),
1875
                         * but it causes a problem because
1876
                         *  (1) PF_EndSort() sets AR.outfile->PObuffer to a send-buffer.
1877
                         *  (2) RevertScratch() clears AR.infile, but then swaps buffers of AR.infile
1878
                         *      and AR.outfile.
1879
                         *  (3) RHS expressions are stored to AR.infile->PObuffer.
1880
                         *  (4) Again, PF_EndSort() sets AR.outfile->PObuffer, but now AR.outfile->PObuffer
1881
                         *      == AR.infile->PObuffer because of (1) and (2).
1882
                         *  (5) The result goes to AR.outfile. This breaks the RHS expressions,
1883
                         *      which may be needed for the next expression.
1884
                         * Solution: backup & restore AR.outfile->PObuffer etc. (TU 14 Sep 2011)
1885
                         */
1886
                        FILEHANDLE *fout = AR.outfile;
6,171✔
1887
                        WORD *oldbuff = fout->PObuffer;
6,171✔
1888
                        WORD *oldstop = fout->POstop;
6,171✔
1889
                        LONG  oldsize = fout->POsize;
6,171✔
1890
                        if ( EndSort(BHEAD AM.S0->sBuffer, 0) < 0 ) return -1;
6,171✔
1891
                        fout->PObuffer = oldbuff;
6,171✔
1892
                        fout->POstop   = oldstop;
6,171✔
1893
                        fout->POsize   = oldsize;
6,171✔
1894
                        fout->POfill = fout->POfull = fout->PObuffer;
6,171✔
1895
                }
1896
                AR.BracketOn = oldBracketOn;
6,171✔
1897
                AT.BrackBuf = oldBrackBuf;
6,171✔
1898
                AT.bracketindexflag = oldbracketindexflag;
6,171✔
1899
/*
1900
                        #] Generator Loop & EndSort : 
1901
                        #[ Collect (stats,prepro...) :
1902
*/
1903
                DBGOUT_NINTERMS(1, ("PF.me=%d AN.ninterms=%d PF_linterms=%d ENDSORT\n", (int)PF.me, (int)AN.ninterms, (int)PF_linterms));
6,171✔
1904
                PF_PrepareLongSinglePack();
6,171✔
1905
                cpu = TimeCPU(1);
6,171✔
1906
                size = 0;
6,171✔
1907
                PF_LongSinglePack(&cpu,              1, PF_LONG);
6,171✔
1908
                PF_LongSinglePack(&size,             1, PF_LONG);
6,171✔
1909
                PF_LongSinglePack(&PF_linterms,      1, PF_LONG);
6,171✔
1910
                PF_LongSinglePack(&AM.S0->GenTerms,  1, PF_LONG);
6,171✔
1911
                PF_LongSinglePack(&AM.S0->TermsLeft, 1, PF_LONG);
6,171✔
1912
                {
1913
                        WORD numdummies = AR.MaxDum - AM.IndDum;
6,171✔
1914
                        PF_LongSinglePack(&numdummies,    1, PF_WORD);
6,171✔
1915
                        PF_LongSinglePack(&AR.expchanged, 1, PF_WORD);
6,171✔
1916
                }
1917
                /* Now handle redefined preprocessor variables. */
1918
                if ( AC.numpfirstnum > 0 ) PF_PackRedefinedPreVars();
6,171✔
1919
                PF_LongSingleSend(MASTER, PF_ENDSORT_MSGTAG);
6,171✔
1920
/*
1921
                        #] Collect (stats,prepro...) : 
1922

1923
                This operation is moved to the beginning of each block, see PreProcessor
1924
                in pre.c.
1925

1926
                 #] Slave : 
1927
*/
1928
                if ( PF.log ) {
6,171✔
1929
                        UBYTE lbuf[24];
×
1930
                        NumToStr(lbuf,AC.CModule);
×
1931
                        fprintf(stderr,"[%d|%s] Endsort,Collect,Broadcast done\n",PF.me,lbuf);
×
1932
                        fflush(stderr);
×
1933
                }
1934
        }
1935
        return(0);
1936
}
1937

1938
/*
1939
                 #] PF_Processor : 
1940
          #] proces.c : 
1941
          #[ startup :, prepro & compile
1942
                 #[ PF_Init :
1943
*/
1944

1945
/**
1946
 * All the library independent stuff.
1947
 * PF_LibInit() should do all library dependent initializations.
1948
 *
1949
 * @param  argc  pointer to the number of arguments.
1950
 * @param  argv  pointer to the arguments.
1951
 * @return       0 if OK, nonzero on error.
1952
 */
1953
int PF_Init(int *argc, char ***argv)
989✔
1954
{
1955
/*
1956
                this should definitely be somewhere else ...
1957
*/
1958
        PF_CurrentBracket = 0;
989✔
1959

1960
        PF.numtasks = 0; /* number of tasks, is determined in PF_LibInit ! */
989✔
1961
        PF.numsbufs = 2; /* might be changed by the environment variable on the master ! */
989✔
1962
        PF.numrbufs = 2; /* might be changed by the environment variable on the master ! */
989✔
1963

1964
        PF_LibInit(argc,argv);
989✔
1965
        PF_RealTime(PF_RESET);
989✔
1966

1967
        PF.log = 0;
989✔
1968
        PF.parallel = 0;
989✔
1969
        PF_statsinterval = 10;
989✔
1970
        PF.rhsInParallel=1;
989✔
1971
        PF.exprbufsize=4096;/*in WORDs*/
989✔
1972

1973
#ifdef PF_WITHGETENV
1974
        if ( PF.me == MASTER ) {
989✔
1975
                char *c;
248✔
1976
/*
1977
                        get these from the environment at the moment should be in setfile/tail
1978
*/
1979
                if ( ( c = getenv("PF_LOG") ) != 0 ) {
248✔
1980
                        if ( *c ) PF.log = (int)atoi(c);
×
1981
                        else PF.log = 1;
×
1982
                        fprintf(stderr,"[%d] changing PF.log to %d\n",PF.me,PF.log);
×
1983
                        fflush(stderr);
×
1984
                }
1985
                if ( ( c = (char*)getenv("PF_RBUFS") ) != 0 ) {
248✔
1986
                        PF.numrbufs = (int)atoi(c);
×
1987
                        fprintf(stderr,"[%d] changing numrbufs to: %d\n",PF.me,PF.numrbufs);
×
1988
                        fflush(stderr);
×
1989
                }
1990
                if ( ( c = (char*)getenv("PF_SBUFS") ) != 0 ) {
248✔
1991
                        PF.numsbufs = (int)atoi(c);
×
1992
                        fprintf(stderr,"[%d] changing numsbufs to: %d\n",PF.me,PF.numsbufs);
×
1993
                        fflush(stderr);
×
1994
                }
1995
                if ( PF.numsbufs > 10 ) PF.numsbufs = 10;
248✔
1996
                if ( PF.numsbufs <  1 ) PF.numsbufs = 1;
248✔
1997
                if ( PF.numrbufs >  2 ) PF.numrbufs = 2;
248✔
1998
                if ( PF.numrbufs <  1 ) PF.numrbufs = 1;
248✔
1999

2000
                if ( ( c = getenv("PF_STATS") ) ) {
248✔
2001
                        UBYTE lbuf[24];
×
2002
                        PF_statsinterval = (int)atoi(c);
×
2003
                        NumToStr(lbuf,PF_statsinterval);
×
2004
                        fprintf(stderr,"[%d] changing PF_statsinterval to %s\n",PF.me,lbuf);
×
2005
                        fflush(stderr);
×
2006
                        if ( PF_statsinterval < 1 ) PF_statsinterval = 10;
×
2007
                }
2008
        }
2009
#endif
2010
/*
2011
          #[ Broadcast settings from getenv: could also be done in PF_DoSetup
2012
*/
2013
        if ( PF.me == MASTER ) {
989✔
2014
                PF_PreparePack();
248✔
2015
                PF_Pack(&PF.log,1,PF_INT);
248✔
2016
                PF_Pack(&PF.numrbufs,1,PF_WORD);
248✔
2017
                PF_Pack(&PF.numsbufs,1,PF_WORD);
248✔
2018
        }
2019
        PF_Broadcast();
989✔
2020
        if ( PF.me != MASTER ) {
989✔
2021
                PF_Unpack(&PF.log,1,PF_INT);
741✔
2022
                PF_Unpack(&PF.numrbufs,1,PF_WORD);
741✔
2023
                PF_Unpack(&PF.numsbufs,1,PF_WORD);
741✔
2024
                if ( PF.log ) {
741✔
2025
                        fprintf(stderr, "[%d] log=%d rbufs=%d sbufs=%d\n",
×
2026
                                PF.me, PF.log, PF.numrbufs, PF.numsbufs);
2027
                        fflush(stderr);
×
2028
                }
2029
        }
2030
/*
2031
          #] Broadcast settings from getenv: 
2032
*/
2033
        return(0);
989✔
2034
}
2035
/*
2036
                 #] PF_Init : 
2037
                 #[ PF_Terminate :
2038
*/
2039

2040
/**
2041
 * Performs the finalization of ParFORM.
2042
 * To be called by Terminate().
2043
 *
2044
 * @param  error  an error code.
2045
 * @return        0 if OK, nonzero on error.
2046
 */
2047
int PF_Terminate(int errorcode)
989✔
2048
{
2049
        return PF_LibTerminate(errorcode);
989✔
2050
}
2051

2052
/*
2053
                 #] PF_Terminate : 
2054
                 #[ PF_GetSlaveTimes :
2055
*/
2056

2057
/**
2058
 * Returns the total CPU time of all slaves together.
2059
 * This function must be called on the master and all slaves.
2060
 *
2061
 * @return  on the master, the sum of CPU times on all slaves.
2062
 */
2063
LONG PF_GetSlaveTimes(void)
2,005✔
2064
{
2065
        LONG slavetimes = 0;
2,005✔
2066
        LONG t = PF.me == MASTER ? 0 : AM.SumTime + TimeCPU(1);
2,005✔
2067
        MPI_Reduce(&t, &slavetimes, 1, PF_LONG, MPI_SUM, MASTER, PF_COMM);
2,005✔
2068
        return slavetimes;
2,005✔
2069
}
2070

2071
/*
2072
                 #] PF_GetSlaveTimes : 
2073
          #] startup : 
2074
          #[ PF_BroadcastNumber :
2075
*/
2076

2077
/**
2078
 * Broadcasts a LONG value from the master to the all slaves.
2079
 *
2080
 * @param  x  the number to be broadcast (set on the master).
2081
 * @return    the synchronised result.
2082
 */
2083
LONG PF_BroadcastNumber(LONG x)
3,007✔
2084
{
2085
#ifdef PF_DEBUG_BCAST_LONG
2086
        if ( PF.me == MASTER ) {
2087
                MesPrint(">> Broadcast LONG: %l", x);
2088
        }
2089
#endif
2090
        PF_Bcast(&x, sizeof(LONG));
3,007✔
2091
        return x;
3,007✔
2092
}
2093

2094
/*
2095
          #] PF_BroadcastNumber : 
2096
          #[ PF_BroadcastBuffer :
2097
*/
2098

2099
/**
2100
 * Broadcasts a buffer from the master to all the slaves.
2101
 *
2102
 * @param[in,out]  buffer  on the master, the buffer to be broadcast. On the
2103
 * slaves, the buffer will be allocated if the length is greater than 0. The
2104
 * caller must free it.
2105
 *
2106
 * @param[in,out]  length  on the master, the length of the buffer to be
2107
 * broadcast. On the slaves, it receives the length of transferred buffer.
2108
 * The actual transfer occurs only if the length is greater than 0.
2109
 */
2110
void PF_BroadcastBuffer(WORD **buffer, LONG *length)
40✔
2111
{
2112
        WORD *p;
40✔
2113
        LONG rest;
40✔
2114
#ifdef PF_DEBUG_BCAST_BUF
2115
        if ( PF.me == MASTER ) {
2116
                MesPrint(">> Broadcast Buffer: length=%l", *length);
2117
        }
2118
#endif
2119
        /* Initialize the buffer on the slaves. */
2120
        if ( PF.me != MASTER ) {
40✔
2121
                *buffer = NULL;
30✔
2122
        }
2123
        /* Broadcast the length of the buffer. */
2124
        *length = PF_BroadcastNumber(*length);
40✔
2125
        if ( *length <= 0 ) return;
40✔
2126
        /* Allocate the buffer on the slaves. */
2127
        if ( PF.me != MASTER ) {
40✔
2128
                *buffer = (WORD *)Malloc1(*length * sizeof(WORD), "PF_BroadcastBuffer");
30✔
2129
        }
2130
        /* Broadcast the data in the buffer. */
2131
        p = *buffer;
40✔
2132
        rest = *length;
40✔
2133
        while ( rest > 0 ) {
80✔
2134
                int l = rest < (LONG)PF.exprbufsize ? (int)rest : PF.exprbufsize;
40✔
2135
                PF_Bcast(p, l * sizeof(WORD));
40✔
2136
                p += l;
40✔
2137
                rest -= l;
40✔
2138
        }
2139
}
2140

2141
/*
2142
          #] PF_BroadcastBuffer : 
2143
          #[ PF_BroadcastString :
2144
*/
2145

2146
/**
2147
 * Broadcasts a string from the master to all slaves.
2148
 *
2149
 * @param[in,out]  str  The pointer to a null-terminated string.
2150
 * @return              0 if OK, nonzero on error.
2151
 */
2152
int PF_BroadcastString(UBYTE *str)
24✔
2153
{
2154
        int clength = 0;
24✔
2155
/*
2156
                If string does not fit to the PF_buffer, it
2157
                will be split into chunks. Next chunk is started at  str+clength
2158
*/
2159
                UBYTE *cstr=str;
24✔
2160
/*
2161
                Note, compilation is performed INDEPENDENTLY on AC.mparallelflag!
2162
                No if ( AC.mparallelflag == PARALLELFLAG ) !!
2163
*/
2164
        do {
24✔
2165
                cstr += clength; /*at each step for all slaves and master */
24✔
2166

2167
                if ( MASTER == PF.me ) { /*Pack str*/
24✔
2168
/*
2169
                                initialize buffers
2170
*/
2171
                        if ( PF_PreparePack() != 0 ) Terminate(-1);
6✔
2172
                        if ( ( clength = PF_PackString(cstr) ) <0  ) Terminate(-1);
6✔
2173
                }
2174
                PF_Broadcast();
24✔
2175

2176
                if ( MASTER != PF.me ) {
24✔
2177
/*
2178
                                Slave - unpack received string
2179
                                For slaves buffers are initialised automatically.
2180
*/
2181
                        if ( ( clength = PF_UnpackString(cstr) ) < 0 ) Terminate(-1);
18✔
2182
                }
2183
        } while ( cstr[clength-1] != '\0' );
24✔
2184
        return (0);
24✔
2185
}
2186

2187
/*
2188
          #] PF_BroadcastString : 
2189
          #[ PF_BroadcastPreDollar :
2190
*/
2191

2192
/**
2193
 * Broadcasts dollar variables set as a preprocessor variables.
2194
 * Only the master is able to make an assignment like #$a=g; where g
2195
 * is an expression: only the master has an access to the expression.
2196
 * So, the master broadcasts the result to slaves.
2197
 *
2198
 * The result is in *dbuffer of the size is *newsize (in number of WORDs),
2199
 * +1 for trailing zero. For slave newsize and numterms are output
2200
 * parameters.
2201
 *
2202
 * @param[in,out]  dbuffer   the buffer for a dollar variable.
2203
 * @param[in,out]  newsize   the size of the dollar variable in WORDs.
2204
 * @param[in,out]  numterms  the number of terms in the dollar variable.
2205
 * @return                   0 if OK, nonzero on error.
2206
 */
2207
int PF_BroadcastPreDollar(WORD **dbuffer, LONG *newsize, int *numterms)
32✔
2208
{
2209
        int err = 0;
32✔
2210
        LONG i;
32✔
2211
/*
2212
                Note, compilation is performed INDEPENDENTLY on AC.mparallelflag!
2213
                No if(AC.mparallelflag==PARALLELFLAG) !!
2214
*/
2215
        if ( MASTER == PF.me ) {
32✔
2216
/*
2217
                        The problem is that sometimes dollar variables are longer
2218
                        than PF_packbuf! So we split long expression into chunks.
2219
                        There are n filled chunks and one partially filled chunk:
2220
*/
2221
                LONG n = ((*newsize)+1)/PF_maxDollarChunkSize;
8✔
2222
/*
2223
                        ...and one more chunk for the rest; if the expression fits to
2224
                        the buffer without splitting, the latter will be the only one.
2225

2226
                        PF_maxDollarChunkSize is the maximal number of items fitted to
2227
                        the buffer. It is calculated in PF_LibInit() in mpi.c.
2228
                        PF_maxDollarChunkSize is calculated for the first step, when
2229
                        two fields (numterms and newsize, see below) are already packed.
2230
                        For simplicity, this value is used also for all steps, in
2231
                        despite  of it is        a bit less than maximally available space.
2232
*/
2233
                WORD *thechunk = *dbuffer;
8✔
2234

2235
                err = PF_PreparePack();             /* initialize buffers */
8✔
2236
                err |= PF_Pack(numterms,1,PF_INT);
8✔
2237
                err |= PF_Pack(newsize,1,PF_LONG); /* pack the size */
8✔
2238
/*
2239
                        Pack and broadcast completely filled chunks.
2240
                        It may happen, this loop is not entered at all:
2241
*/
2242
                for ( i = 0; i < n; i++ ) {
10✔
2243
                        err |= PF_Pack(thechunk,PF_maxDollarChunkSize,PF_WORD);
2✔
2244
                        err |= PF_Broadcast();
2✔
2245
                        thechunk +=PF_maxDollarChunkSize;
2✔
2246
                        PF_PreparePack();
2✔
2247
                }
2248
/*
2249
                        Pack and broadcast the rest:
2250
*/
2251
                if ( ( n = ( (*newsize)+1)%PF_maxDollarChunkSize ) != 0 ) {
8✔
2252
                        err |= PF_Pack(thechunk,n,PF_WORD);
8✔
2253
                        err |= PF_Broadcast();
8✔
2254
                }
2255
#ifdef PF_DEBUG_BCAST_PREDOLLAR
2256
                MesPrint(">> Broadcast PreDollar: newsize=%d numterms=%d", (int)*newsize, *numterms);
2257
#endif
2258
        }
2259
        if ( MASTER != PF.me ) {  /* Slave - unpack received buffer */
32✔
2260
                WORD *thechunk;
24✔
2261
                LONG n, therest, thesize;
24✔
2262
                err |= PF_Broadcast();
24✔
2263
                err |=PF_Unpack(numterms,1,PF_INT);
24✔
2264
                err |=PF_Unpack(newsize,1,PF_LONG);
24✔
2265
/*
2266
                        Now we know the buffer size.
2267
*/
2268
                thesize = (*newsize)+1;
24✔
2269
/*
2270
                        Evaluate the number of completely filled chunks. The last step must be
2271
                        treated separately, so -1:
2272
*/
2273
                n = (thesize/PF_maxDollarChunkSize) - 1;
24✔
2274
/*
2275
                        Note, here n can be <0, this is ok.
2276
*/
2277
                therest = thesize % PF_maxDollarChunkSize;
24✔
2278
                thechunk = *dbuffer =
48✔
2279
                        (WORD*)Malloc1( thesize * sizeof(WORD),"$-buffer slave");
24✔
2280
                if ( thechunk == NULL ) return(err|4);
24✔
2281
/*
2282
                        Unpack completely filled chunks and receive the next portion.
2283
                        It may happen, this loop is not entered at all:
2284
*/
2285
                for ( i = 0; i < n; i++ ) {
27✔
2286
                        err |= PF_Unpack(thechunk,PF_maxDollarChunkSize,PF_WORD);
3✔
2287
                        thechunk += PF_maxDollarChunkSize;
3✔
2288
                        err |= PF_Broadcast();
3✔
2289
                }
2290
/*
2291
                        Now the last completely filled chunk:
2292
*/
2293
                if ( n >= 0 ) {
24✔
2294
                        err |= PF_Unpack(thechunk,PF_maxDollarChunkSize,PF_WORD);
3✔
2295
                        thechunk += PF_maxDollarChunkSize;
3✔
2296
                        if ( therest != 0 ) err |= PF_Broadcast();
3✔
2297
                }
2298
/*
2299
                        Unpack the rest (it is already received!):
2300
*/
2301
                if ( therest != 0 ) err |= PF_Unpack(thechunk,therest,PF_WORD);
24✔
2302
        }
2303
        return (err);
2304
}
2305

2306
/*
2307
          #] PF_BroadcastPreDollar : 
2308
          #[ Synchronization of modified dollar variables :
2309
                 #[ Helper functions :
2310
                        #[ dollarlen :
2311
*/
2312

2313
/**
2314
 * Returns the size of \a terms in WORDs, not including the null terminator.
2315
 */
2316
static inline LONG dollarlen(const WORD *terms)
56✔
2317
{
2318
        const WORD *p = terms;
56✔
2319
        while ( *p ) p += *p;
124✔
2320
        return p - terms;  /* Not including the null terminator. */
56✔
2321
}
2322

2323
/*
2324
                        #] dollarlen : 
2325
                        #[ dollar_mod_type :
2326
*/
2327

2328
/**
2329
 * Returns the module option type of a dollar variable specified by \a index.
2330
 * If no module option is given for the variable, this function returns -1.
2331
 */
2332
static inline WORD dollar_mod_type(WORD index)
572✔
2333
{
2334
        int i;
572✔
2335
        for ( i = 0; i < NumModOptdollars; i++ )
772✔
2336
                if ( ModOptdollars[i].number == index ) break;
644✔
2337
        if ( i >= NumModOptdollars ) return -1;
572✔
2338
        return ModOptdollars[i].type;
245✔
2339
}
2340

2341

2342
/*
2343
                        #] dollar_mod_type : 
2344
                 #] Helper functions : 
2345
                 #[ PF_CollectModifiedDollars :
2346
*/
2347

2348
/*
2349
                        #[ dollar_to_be_collected :
2350
*/
2351

2352
/**
2353
 * Returns true if the dollar variable specified by \a index has to be collected
2354
 * from each slave to the master, i.e., declared as MODSUM, MODMAX or MODMIN.
2355
 */
2356
static inline int dollar_to_be_collected(WORD index)
245✔
2357
{
2358
        switch ( dollar_mod_type(index) ) {
490✔
2359
                case MODSUM:
2360
                case MODMAX:
2361
                case MODMIN:
2362
                        return 1;
2363
                default:
124✔
2364
                        return 0;
124✔
2365
        }
2366
}
2367

2368
/*
2369
                        #] dollar_to_be_collected : 
2370
                        #[ copy_dollar :
2371
*/
2372

2373
/**
2374
 * Copy the data given by \a type, \a where and \a size to a dollar variable
2375
 * specified by \a index.
2376
 */
2377
static inline void copy_dollar(WORD index, WORD type, const WORD *where, LONG size)
11✔
2378
{
2379
        DOLLARS d = Dollars + index;
11✔
2380

2381
        CleanDollarFactors(d);
11✔
2382

2383
        if ( type != DOLZERO && where != NULL && where != &AM.dollarzero && where[0] != 0 && size > 0 ) {
11✔
2384
                if ( size > d->size || size < d->size / 4 ) {  /* Reallocate if not enough or too much. */
10✔
2385
                        if ( d->where && d->where != &AM.dollarzero )
10✔
2386
                                M_free(d->where, "old content of dollar");
10✔
2387
                        d->where = Malloc1(sizeof(WORD) * size, "copy buffer to dollar");
10✔
2388
                        d->size  = size;
10✔
2389
                }
2390
                d->type  = type;
10✔
2391
                WCOPY(d->where, where, size);
60✔
2392
        }
2393
        else {
2394
                if ( d->where && d->where != &AM.dollarzero )
1✔
2395
                        M_free(d->where, "old content of dollar");
1✔
2396
                d->type  = DOLZERO;
1✔
2397
                d->where = &AM.dollarzero;
1✔
2398
                d->size  = 0;
1✔
2399
        }
2400
}
11✔
2401

2402
/*
2403
                        #] copy_dollar : 
2404
                        #[ compare_two_expressions :
2405
*/
2406

2407
/**
2408
 * Compares two expressions \a e1 and \a e2 and returns a positive value if
2409
 * \a e1 > \a e2, a negative value if \a e1 < \a e2, or zero if \a e1 == \a e2.
2410
 */
2411
static inline int compare_two_expressions(const WORD *e1, const WORD *e2)
20✔
2412
{
2413
        GETIDENTITY
2414
        /*
2415
         * We consider the cases that
2416
         *   (1) the expression has no term,
2417
         *   (2) the expression has only one term and it is a number,
2418
         *   (3) otherwise.
2419
         * Assume that the expressions are sorted and all terms are normalized.
2420
         * The numerators of the coefficients must never be zero.
2421
         *
2422
         * Note that TwoExprCompare() is not adequate for our purpose
2423
         * (as of 6 Aug. 2013), e.g., TwoExprCompare({0}, {4, 1, 1, -1}, LESS)
2424
         * returns TRUE.
2425
         */
2426
        if ( e1[0] == 0 ) {
20✔
2427
                if ( e2[0] == 0 ) {
3✔
2428
                        return(0);
2429
                }
2430
                else if ( e2[e2[0]] == 0 && e2[0] == ABS(e2[e2[0] - 1]) + 1 ) {
1✔
2431
                        if ( e2[e2[0] - 1] > 0 )
1✔
2432
                                return(-1);
2433
                        else
UNCOV
2434
                                return(+1);
×
2435
                }
2436
        }
2437
        else if ( e1[e1[0]] == 0 && e1[0] == ABS(e1[e1[0] - 1]) + 1 ) {
17✔
2438
                if ( e2[0] == 0 ) {
17✔
UNCOV
2439
                        if ( e1[e1[0] - 1] > 0 )
×
2440
                                return(+1);
2441
                        else
2442
                                return(-1);
×
2443
                }
2444
                else if ( e2[e2[0]] == 0 && e2[0] == ABS(e2[e2[0] - 1]) + 1 ) {
17✔
2445
                        return(CompCoef((WORD *)e1, (WORD *)e2));
17✔
2446
                }
2447
        }
2448
        /* The expressions are not so simple. Define the order by each term. */
2449
        while ( e1[0] && e2[0] ) {
×
2450
                int c = CompareTerms(BHEAD (WORD *)e1, (WORD *)e2, 1);
×
2451
                if ( c < 0 )
×
2452
                        return(-1);
2453
                else if ( c > 0 )
×
2454
                        return(+1);
2455
                e1 += e1[0];
×
2456
                e2 += e2[0];
×
2457
        }
2458
        if ( e1[0] ) return(+1);
×
2459
        if ( e2[0] ) return(-1);
×
2460
        return(0);
2461
}
2462

2463
/*
2464
                        #] compare_two_expressions : 
2465
                        #[ Variables :
2466
*/
2467

2468
typedef struct {
2469
        VectorStruct(WORD) buf;
2470
        LONG size;
2471
        WORD type;
2472
        PADPOINTER(1,0,1,0);
2473
} dollar_buf;
2474

2475
/* Buffers used to store data for each variable from each slave. */
2476
static Vector(dollar_buf, dollar_slave_bufs);
2477

2478
/*
2479
                        #] Variables : 
2480
*/
2481

2482
/**
2483
 * Combines modified dollar variables on the all slaves, and store them into
2484
 * those on the master.
2485
 *
2486
 * The potentially modified dollar variables are given in PotModdollars,
2487
 * and the number of them is given by NumPotModdollars.
2488
 *
2489
 * The current module could be executed in parallel only if all potentially
2490
 * modified variables are listed in ModOptdollars, otherwise the module was
2491
 * switched to the sequential mode.
2492
 *
2493
 * @return  0 if OK, nonzero on error.
2494
 */
2495
int PF_CollectModifiedDollars(void)
112✔
2496
{
2497
        int i, j, ndollars;
112✔
2498
        /*
2499
         * If the current module was executed in the sequential mode,
2500
         * there are no modified module on the slaves.
2501
         */
2502
        if ( AC.mparallelflag != PARALLELFLAG && !AC.partodoflag ) return 0;
112✔
2503
        /*
2504
         * Count the number of (potentially) modified dollar variables, which we need to collect.
2505
         * Here we need to collect all max/min/sum variables.
2506
         */
2507
        ndollars = 0;
2508
        for ( i = 0; i < NumPotModdollars; i++ ) {
180✔
2509
                WORD index = PotModdollars[i];
112✔
2510
                if ( dollar_to_be_collected(index) ) ndollars++;
112✔
2511
        }
2512
        if ( ndollars == 0 ) return 0;  /* No dollars to be collected. */
68✔
2513

2514
        if ( PF.me == MASTER ) {
40✔
2515
/*
2516
                        #[ Master :
2517
*/
2518
                int nslaves, nvars;
10✔
2519
                /* Prepare receive buffers. We need ndollars*(PF.numtasks-1) buffers. */
2520
                int nbufs = ndollars * (PF.numtasks - 1);
10✔
2521
                VectorReserve(dollar_slave_bufs, nbufs);
10✔
2522
                for ( i = VectorSize(dollar_slave_bufs); i < nbufs; i++ ) {
19✔
2523
                        VectorInit(VectorPtr(dollar_slave_bufs)[i].buf);
9✔
2524
                }
2525
                VectorSize(dollar_slave_bufs) = nbufs;
10✔
2526
                /* Receive data from each slave. */
2527
                for ( nslaves = 1; nslaves < PF.numtasks; nslaves++ ) {
40✔
2528
                        int src;
30✔
2529
                        PF_LongSingleReceive(PF_ANY_SOURCE, PF_DOLLAR_MSGTAG, &src, NULL);
30✔
2530
                        nvars = 0;
30✔
2531
                        for ( i = 0; i < NumPotModdollars; i++ ) {
117✔
2532
                                WORD index = PotModdollars[i];
57✔
2533
                                dollar_buf *b;
57✔
2534
                                if ( !dollar_to_be_collected(index) ) continue;
57✔
2535
                                b = &VectorPtr(dollar_slave_bufs)[(PF.numtasks - 1) * nvars + (src - 1)];
33✔
2536
                                PF_LongSingleUnpack(&b->type, 1, PF_WORD);
33✔
2537
                                if ( b->type != DOLZERO ) {
33✔
2538
                                        LONG size;
29✔
2539
                                        WORD *where;
29✔
2540
                                        PF_LongSingleUnpack(&size, 1, PF_LONG);
29✔
2541
                                        VectorReserve(b->buf, size + 1);
29✔
2542
                                        where = VectorPtr(b->buf);
29✔
2543
                                        PF_LongSingleUnpack(where, size, PF_WORD);
29✔
2544
                                        where[size] = 0;  /* The null terminator is needed. */
29✔
2545
                                        b->size = size + 1;  /* Including the null terminator. */
29✔
2546
                                        /* Note that we don't collect factored stuff for max/min/sum variables. */
2547
                                }
2548
                                else {
2549
                                        VectorReserve(b->buf, 1);
4✔
2550
                                        VectorPtr(b->buf)[0] = 0;
4✔
2551
                                        b->size = 0;
4✔
2552
                                }
2553
                                nvars++;
33✔
2554
                        }
2555
                }
2556
                /*
2557
                 * Combine received dollars. The FORM reference manual says maximum/minimum/sum
2558
                 * $-variables must have a numerical value, however, this routine should work also
2559
                 * for non-numerical cases, although the maximum/minimum value for non-numerical
2560
                 * terms has ambiguity.
2561
                 */
2562
                nvars = 0;
2563
                for ( i = 0; i < NumPotModdollars; i++ ) {
29✔
2564
                        WORD index = PotModdollars[i];
19✔
2565
                        WORD dtype;
19✔
2566
                        DOLLARS d;
19✔
2567
                        dollar_buf *b;
19✔
2568
                        if ( !dollar_to_be_collected(index) ) continue;
19✔
2569
                        d = Dollars + index;
11✔
2570
                        b = &VectorPtr(dollar_slave_bufs)[(PF.numtasks - 1) * nvars];
11✔
2571
                        dtype = dollar_mod_type(index);
11✔
2572
                        switch ( dtype ) {
11✔
2573
                                case MODMAX:
2574
                                case MODMIN: {
2575
/*
2576
                        #[ MODMAX & MODMIN :
2577
*/
2578
                                        int selected = 0;
2579
                                        for ( j = 1; j < PF.numtasks - 1; j++ ) {
30✔
2580
                                                int c = compare_two_expressions(VectorPtr(b[j].buf), VectorPtr(b[selected].buf));
20✔
2581
                                                if ( (dtype == MODMAX && c > 0) || (dtype == MODMIN && c < 0) )
20✔
2582
                                                        selected = j;
6✔
2583
                                        }
2584
                                        b = b + selected;
10✔
2585
                                        copy_dollar(index, b->type, VectorPtr(b->buf), b->size);
10✔
2586
/*
2587
                        #] MODMAX & MODMIN : 
2588
*/
2589
                                        break;
10✔
2590
                                }
2591
                                case MODSUM: {
1✔
2592
/*
2593
                        #[ MODSUM :
2594
*/
2595
                                        GETIDENTITY
2596
                                        int err = 0;
1✔
2597

2598
                                        CBUF *C = cbuf + AM.rbufnum;
1✔
2599
                                        WORD *oldwork = AT.WorkPointer, *oldcterm = AN.cTerm;
1✔
2600
                                        WORD olddefer = AR.DeferFlag, oldnumlhs = AR.Cnumlhs, oldnumrhs = C->numrhs;
1✔
2601

2602
                                        LONG size;
1✔
2603
                                        WORD type, *dbuf;
1✔
2604

2605
                                        AN.cTerm = 0;
1✔
2606
                                        AR.DeferFlag = 0;
1✔
2607

2608
                                        if ( ((WORD *)((UBYTE *)AT.WorkPointer + AM.MaxTer)) > AT.WorkTop ) {
1✔
2609
                                                err = -1;
×
2610
                                                goto cleanup;
×
2611
                                                MesWork();
2612
                                        }
2613

2614
                                        if ( NewSort(BHEAD0) ) {
1✔
2615
                                                err = -1;
×
2616
                                                goto cleanup;
×
2617
                                        }
2618
                                        if ( NewSort(BHEAD0) ) {
1✔
2619
                                                LowerSortLevel();
×
2620
                                                err = -1;
×
2621
                                                goto cleanup;
×
2622
                                        }
2623

2624
                                        /*
2625
                                         * Sum up the original $-variable in the master and $-variables on all slaves.
2626
                                         * Note that $-variables on the slaves are set to zero at the beginning of
2627
                                         * the module (See also DoExecute()).
2628
                                         */
2629
                                        for ( j = 0; j < PF.numtasks; j++ ) {
5✔
2630
                                                const WORD *r;
4✔
2631
                                                for ( r = j == 0 ? Dollars[index].where : VectorPtr(b[j - 1].buf); *r; r += *r ) {
11✔
2632
                                                        WCOPY(AT.WorkPointer, r, *r);
15✔
2633
                                                        AT.WorkPointer += *r;
3✔
2634
                                                        AR.Cnumlhs = 0;
3✔
2635
                                                        if ( Generator(BHEAD oldwork, 0) ) {
3✔
2636
                                                                LowerSortLevel(); LowerSortLevel();
×
2637
                                                                err = -1;
×
2638
                                                                goto cleanup;
×
2639
                                                        }
2640
                                                        AT.WorkPointer = oldwork;
3✔
2641
                                                }
2642
                                        }
2643

2644
                                        size = EndSort(BHEAD (WORD *)&dbuf, 2);
1✔
2645
                                        if ( size < 0 ) {
1✔
2646
                                                LowerSortLevel();
×
2647
                                                err = -1;
×
2648
                                                goto cleanup;
×
2649
                                        }
2650
                                        LowerSortLevel();
1✔
2651

2652
                                        /* Find special cases. */
2653
                                        type = DOLTERMS;
1✔
2654
                                        if ( dbuf[0] == 0 ) {
1✔
2655
                                                type = DOLZERO;
2656
                                        }
2657
                                        else if ( dbuf[dbuf[0]] == 0 ) {
1✔
2658
                                                const WORD *t = dbuf, *w;
1✔
2659
                                                WORD n, nsize;
1✔
2660
                                                n = *t;
1✔
2661
                                                nsize = t[n - 1];
1✔
2662
                                                if ( nsize < 0 ) nsize = -nsize;
1✔
2663
                                                if ( nsize == n - 1 ) {
1✔
2664
                                                        nsize = (nsize - 1) / 2;
1✔
2665
                                                        w = t + 1 + nsize;
1✔
2666
                                                        if ( *w == 1 ) {
1✔
2667
                                                                w++; while ( w < t + n - 1 ) { if ( *w ) break; w++; }
1✔
2668
                                                                if ( w >= t + n - 1 ) type =  DOLNUMBER;
1✔
2669
                                                        }
2670
                                                        else if ( n == 7 && t[6] == 3 && t[5] == 1 && t[4] == 1 && t[1] == INDEX && t[2] == 3 ) {
×
2671
                                                                type = DOLINDEX;
×
2672
                                                                d->index = t[3];
×
2673
                                                        }
2674
                                                }
2675
                                        }
2676
                                        copy_dollar(index, type, dbuf, dollarlen(dbuf) + 1);
2✔
2677
                                        M_free(dbuf, "temporary dollar buffer");
1✔
2678
cleanup:
1✔
2679
                                        AR.Cnumlhs = oldnumlhs;
1✔
2680
                                        C->numrhs = oldnumrhs;
1✔
2681
                                        AR.DeferFlag = olddefer;
1✔
2682
                                        AN.cTerm = oldcterm;
1✔
2683
                                        AT.WorkPointer = oldwork;
1✔
2684

2685
                                        if ( err ) return err;
1✔
2686
/*
2687
                        #] MODSUM : 
2688
*/
2689
                                        break;
1✔
2690
                                }
2691
                        }
2692
                        if ( d->type == DOLTERMS )
11✔
2693
                                cbuf[AM.dbufnum].CanCommu[index] = numcommute(d->where, &cbuf[AM.dbufnum].NumTerms[index]);
×
2694
                        cbuf[AM.dbufnum].rhs[index] = d->where;
11✔
2695
                        nvars++;
11✔
2696
#ifdef PF_DEBUG_REDUCE_DOLLAR
2697
                        MesPrint("<< Reduce $-var: %s", AC.dollarnames->namebuffer + d->name);
2698
#endif
2699
                }
2700
/*
2701
                        #] Master : 
2702
*/
2703
        }
2704
        else {
2705
/*
2706
                        #[ Slave :
2707
*/
2708
                PF_PrepareLongSinglePack();
30✔
2709
                /* Pack each variable. */
2710
                for ( i = 0; i < NumPotModdollars; i++ ) {
117✔
2711
                        WORD index = PotModdollars[i];
57✔
2712
                        DOLLARS d;
57✔
2713
                        if ( !dollar_to_be_collected(index) ) continue;
57✔
2714
                        d = Dollars + index;
33✔
2715
                        PF_LongSinglePack(&d->type, 1, PF_WORD);
33✔
2716
                        if ( d->type != DOLZERO ) {
33✔
2717
                                /*
2718
                                 * NOTE: d->size is the allocated buffer size for d->where in WORDs.
2719
                                 *       So dollarlen(d->where) can be < d->size-1. (TU 15 Dec 2011)
2720
                                 */
2721
                                LONG size = dollarlen(d->where);
29✔
2722
                                PF_LongSinglePack(&size, 1, PF_LONG);
29✔
2723
                                PF_LongSinglePack(d->where, size, PF_WORD);
29✔
2724
                                /* Note that we don't collect factored stuff for max/min/sum variables. */
2725
                        }
2726
                }
2727
                PF_LongSingleSend(MASTER, PF_DOLLAR_MSGTAG);
30✔
2728
/*
2729
                        #] Slave : 
2730
*/
2731
        }
2732
        return 0;
2733
}
2734

2735
/*
2736
                 #] PF_CollectModifiedDollars : 
2737
                 #[ PF_BroadcastModifiedDollars :
2738
*/
2739

2740
/*
2741
                        #[ dollar_to_be_broadcast :
2742
*/
2743

2744
/**
2745
 * Returns true if the dollar variable specified by \a index has to be broadcast
2746
 * from the master to the all slaves, i.e., non-local.
2747
 */
2748
static inline int dollar_to_be_broadcast(WORD index)
316✔
2749
{
2750
        switch ( dollar_mod_type(index) ) {
504✔
2751
                case MODLOCAL:
2752
                        return 0;
2753
                default:
216✔
2754
                        return 1;
216✔
2755
        }
2756
}
2757

2758
/*
2759
                        #] dollar_to_be_broadcast : 
2760
*/
2761

2762
/**
2763
 * Broadcasts modified dollar variables on the master to the all slaves.
2764
 *
2765
 * The potentially modified dollar variables are given in PotModdollars,
2766
 * and the number of them is given by NumPotModdollars.
2767
 *
2768
 * The current module could be executed in parallel only if all potentially
2769
 * modified variables are listed in ModOptdollars, otherwise the module was
2770
 * switched to the sequential mode. In either cases, we need to broadcast them.
2771
 *
2772
 * @return  0 if OK, nonzero on error.
2773
 */
2774
int PF_BroadcastModifiedDollars(void)
112✔
2775
{
2776
        int i, j, ndollars;
112✔
2777
        /*
2778
         * Count the number of (potentially) modified dollar variables, which we need to broadcast.
2779
         * Here we need to broadcast all non-local variables.
2780
         */
2781
        ndollars = 0;
112✔
2782
        for ( i = 0; i < NumPotModdollars; i++ ) {
288✔
2783
                WORD index = PotModdollars[i];
176✔
2784
                if ( dollar_to_be_broadcast(index) ) ndollars++;
176✔
2785
        }
2786
        if ( ndollars == 0 ) return 0;  /* No dollars to be broadcast. */
112✔
2787

2788
        if ( PF.me == MASTER ) {
84✔
2789
/*
2790
                        #[ Master :
2791
*/
2792
                PF_PrepareLongMultiPack();
21✔
2793
                /* Pack each variable. */
2794
                for ( i = 0; i < NumPotModdollars; i++ ) {
77✔
2795
                        WORD index = PotModdollars[i];
35✔
2796
                        DOLLARS d;
35✔
2797
                        if ( !dollar_to_be_broadcast(index) ) continue;
35✔
2798
                        d = Dollars + index;
27✔
2799
                        PF_LongMultiPack(&d->type, 1, PF_WORD);
27✔
2800
                        if ( d->type != DOLZERO ) {
27✔
2801
                                /*
2802
                                 * NOTE: d->size is the allocated buffer size for d->where in WORDs.
2803
                                 *       So dollarlen(d->where) can be < d->size-1. (TU 15 Dec 2011)
2804
                                 */
2805
                                LONG size = dollarlen(d->where);
26✔
2806
                                PF_LongMultiPack(&size, 1, PF_LONG);
26✔
2807
                                PF_LongMultiPack(d->where, size, PF_WORD);
26✔
2808
                                /* ...and the factored stuff. */
2809
                                PF_LongMultiPack(&d->nfactors, 1, PF_WORD);
26✔
2810
                                if ( d->nfactors > 1 ) {
26✔
2811
                                        for ( j = 0; j < d->nfactors; j++ ) {
6✔
2812
                                                FACDOLLAR *f = &d->factors[j];
5✔
2813
                                                PF_LongMultiPack(&f->type, 1, PF_WORD);
5✔
2814
                                                PF_LongMultiPack(&f->size, 1, PF_LONG);
5✔
2815
                                                if ( f->size > 0 )
5✔
2816
                                                        PF_LongMultiPack(f->where, f->size, PF_WORD);
4✔
2817
                                                else
2818
                                                        PF_LongMultiPack(&f->value, 1, PF_WORD);
1✔
2819
                                        }
2820
                                }
2821
                        }
2822
#ifdef PF_DEBUG_BCAST_DOLLAR
2823
                        MesPrint(">> Broadcast $-var: %s", AC.dollarnames->namebuffer + d->name);
2824
#endif
2825
                }
2826
/*
2827
                        #] Master : 
2828
*/
2829
        }
2830
        if ( PF_LongMultiBroadcast() ) return -1;
84✔
2831
        if ( PF.me != MASTER ) {
84✔
2832
/*
2833
                        #[ Slave :
2834
*/
2835
                for ( i = 0; i < NumPotModdollars; i++ ) {
168✔
2836
                        WORD index = PotModdollars[i];
105✔
2837
                        DOLLARS d;
105✔
2838
                        if ( !dollar_to_be_broadcast(index) ) continue;
105✔
2839
                        d = Dollars + index;
81✔
2840
                        /* Clear the contents of the dollar variable. */
2841
                        if ( d->where && d->where != &AM.dollarzero )
81✔
2842
                                M_free(d->where, "old content of dollar");
42✔
2843
                        d->where = &AM.dollarzero;
81✔
2844
                        d->size = 0;
81✔
2845
                        CleanDollarFactors(d);
81✔
2846
                        /* Unpack and store the contents. */
2847
                        PF_LongMultiUnpack(&d->type, 1, PF_WORD);
81✔
2848
                        if ( d->type != DOLZERO ) {
81✔
2849
                                LONG size;
78✔
2850
                                PF_LongMultiUnpack(&size, 1, PF_LONG);
78✔
2851
                                d->size = size + 1;
78✔
2852
                                d->where = (WORD *)Malloc1(sizeof(WORD) * d->size, "dollar content");
78✔
2853
                                PF_LongMultiUnpack(d->where, size, PF_WORD);
78✔
2854
                                d->where[size] = 0;  /* The null terminator is needed. */
78✔
2855
                                /* ...and the factored stuff. */
2856
                                PF_LongMultiUnpack(&d->nfactors, 1, PF_WORD);
78✔
2857
                                if ( d->nfactors > 1 ) {
78✔
2858
                                        d->factors = (FACDOLLAR *)Malloc1(sizeof(FACDOLLAR) * d->nfactors, "dollar factored stuff");
3✔
2859
                                        for ( j = 0; j < d->nfactors; j++ ) {
18✔
2860
                                                FACDOLLAR *f = &d->factors[j];
15✔
2861
                                                PF_LongMultiUnpack(&f->type, 1, PF_WORD);
15✔
2862
                                                PF_LongMultiUnpack(&f->size, 1, PF_LONG);
15✔
2863
                                                if ( f->size > 0 ) {
15✔
2864
                                                        f->where = (WORD *)Malloc1(sizeof(WORD) * (f->size + 1), "dollar factor content");
12✔
2865
                                                        PF_LongMultiUnpack(f->where, f->size, PF_WORD);
12✔
2866
                                                        f->where[f->size] = 0;  /* The null terminator is needed. */
12✔
2867
                                                        f->value = 0;
12✔
2868
                                                }
2869
                                                else {
2870
                                                        f->where = NULL;
3✔
2871
                                                        PF_LongMultiUnpack(&f->value, 1, PF_WORD);
3✔
2872
                                                }
2873
                                        }
2874
                                }
2875
                        }
2876
                        if ( d->type == DOLTERMS )
81✔
2877
                                cbuf[AM.dbufnum].CanCommu[index] = numcommute(d->where, &cbuf[AM.dbufnum].NumTerms[index]);
21✔
2878
                        cbuf[AM.dbufnum].rhs[index] = d->where;
81✔
2879
                }
2880
/*
2881
                        #] Slave : 
2882
*/
2883
        }
2884
        return 0;
2885
}
2886

2887
/*
2888
                 #] PF_BroadcastModifiedDollars : 
2889
          #] Synchronization of modified dollar variables : 
2890
          #[ Synchronization of redefined preprocessor variables :
2891
                 #[ Variables :
2892
*/
2893

2894
/* A buffer used in receivers. */
2895
static Vector(UBYTE, prevarbuf);
2896

2897
/*
2898
                 #] Variables : 
2899
                 #[ PF_PackRedefinedPreVars :
2900
*/
2901

2902
/**
2903
 * Packs information of redefined preprocessor variables into the long single
2904
 * pack buffer, with the corresponding value in AC.inputnumbers.
2905
 *
2906
 * The potentially redefined preprocessor variables are given in AC.pfirstnum,
2907
 * and the number of them is given by AC.numpfirstnum. For an actually redefined
2908
 * variable, the corresponding value in AC.inputnumbers is non-negative.
2909
 */
2910
static void PF_PackRedefinedPreVars(void)
12✔
2911
{
2912
        int i;
12✔
2913
        /* First, pack the number of redefined preprocessor variables. */
2914
        int nredefs = 0;
12✔
2915
        for ( i = 0; i < AC.numpfirstnum; i++ )
24✔
2916
                if ( AC.inputnumbers[i] >= 0 ) nredefs++;
12✔
2917
        PF_LongSinglePack(&nredefs, 1, PF_INT);
12✔
2918
        /* Then, pack each variable. */
2919
        for ( i = 0; i < AC.numpfirstnum; i++ )
36✔
2920
                if ( AC.inputnumbers[i] >= 0) {
12✔
2921
                        WORD index = AC.pfirstnum[i];
6✔
2922
                        UBYTE *value = PreVar[index].value;
6✔
2923
                        int bytes = strlen((char *)value);
6✔
2924
                        PF_LongSinglePack(&index, 1, PF_WORD);
6✔
2925
                        PF_LongSinglePack(&bytes, 1, PF_INT);
6✔
2926
                        PF_LongSinglePack(value, bytes, PF_BYTE);
6✔
2927
                        PF_LongSinglePack(&AC.inputnumbers[i], 1, PF_LONG);
6✔
2928
        }
2929
}
12✔
2930

2931
/*
2932
                 #] PF_PackRedefinedPreVars : 
2933
                 #[ PF_UnpackRedefinedPreVars :
2934
*/
2935

2936
/**
2937
 * Unpacks information of redefined preprocessor variables from the long single
2938
 * pack buffer. If the attached value of the input number is greater than
2939
 * the corresponding current value in AC.inputnumbers, this function updates
2940
 * the preprocessor variable.
2941
 *
2942
 * The potentially redefined preprocessor variables are given in AC.pfirstnum,
2943
 * and the number of them is AC.numpfirstnum.
2944
 */
2945
static void PF_UnpackRedefinedPreVars(void)
12✔
2946
{
2947
        int i, j;
12✔
2948
        /* Unpack the number of redefined preprocessor variables. */
2949
        int nredefs;
12✔
2950
        PF_LongSingleUnpack(&nredefs, 1, PF_INT);
12✔
2951
        if ( nredefs > 0 ) {
12✔
2952
                /* Then unpack each variable. */
2953
                for ( i = 0; i < nredefs; i++ ) {
12✔
2954
                        WORD index;
6✔
2955
                        int bytes;
6✔
2956
                        UBYTE *value;
6✔
2957
                        LONG inputnumber;
6✔
2958
                        PF_LongSingleUnpack(&index, 1, PF_WORD);
6✔
2959
                        PF_LongSingleUnpack(&bytes, 1, PF_INT);
6✔
2960
                        VectorReserve(prevarbuf, bytes + 1);
6✔
2961
                        value = VectorPtr(prevarbuf);
6✔
2962
                        PF_LongSingleUnpack(value, bytes, PF_BYTE);
6✔
2963
                        value[bytes] = '\0';  /* The null terminator is needed. */
6✔
2964
                        PF_LongSingleUnpack(&inputnumber, 1, PF_LONG);
6✔
2965
                        /* Put this variable if it must be updated. */
2966
                        for ( j = 0; j < AC.numpfirstnum; j++ )
12✔
2967
                                if ( AC.pfirstnum[j] == index ) break;
6✔
2968
                        if ( AC.inputnumbers[j] < inputnumber ) {
6✔
2969
                                AC.inputnumbers[j] = inputnumber;
3✔
2970
                                PutPreVar(PreVar[index].name, value, NULL, 1);
3✔
2971
                        }
2972
                }
2973
        }
2974
}
12✔
2975

2976
/*
2977
                 #] PF_UnpackRedefinedPreVars : 
2978
                 #[ PF_BroadcastRedefinedPreVars :
2979
*/
2980

2981
/**
2982
 * Broadcasts preprocessor variables, which were changed by the Redefine statements
2983
 * in the current module, from the master to the all slaves.
2984
 *
2985
 * The potentially redefined preprocessor variables are given in AC.pfirstnum,
2986
 * and the number of them is given by AC.numpfirstnum. For an actually redefined
2987
 * variable, the corresponding value in AC.inputnumbers is non-negative.
2988
 *
2989
 * @return  0 if OK, nonzero on error.
2990
 */
2991
int PF_BroadcastRedefinedPreVars(void)
20✔
2992
{
2993
        /*
2994
         * NOTE: Because the compilation is performed on the all processes
2995
         * independently on AC.mparallelflag, we always have to broadcast redefined
2996
         * preprocessor variables from the master to the all slaves.
2997
         */
2998
        if ( PF.me == MASTER ) {
20✔
2999
/*
3000
                        #[ Master :
3001
*/
3002
                int i, nredefs;
5✔
3003
                PF_PrepareLongMultiPack();
5✔
3004
                /* First, pack the number of redefined preprocessor variables. */
3005
                nredefs = 0;
5✔
3006
                for ( i = 0; i < AC.numpfirstnum; i++ )
10✔
3007
                        if ( AC.inputnumbers[i] >= 0 ) nredefs++;
5✔
3008
                PF_LongMultiPack(&nredefs, 1, PF_INT);
5✔
3009
                /* Then, pack each variable. */
3010
                for ( i = 0; i < AC.numpfirstnum; i++ )
15✔
3011
                        if ( AC.inputnumbers[i] >= 0) {
5✔
3012
                                WORD index = AC.pfirstnum[i];
3✔
3013
                                UBYTE *value = PreVar[index].value;
3✔
3014
                                int bytes = strlen((char *)value);
3✔
3015
                                PF_LongMultiPack(&index, 1, PF_WORD);
3✔
3016
                                PF_LongMultiPack(&bytes, 1, PF_INT);
3✔
3017
                                PF_LongMultiPack(value, bytes, PF_BYTE);
3✔
3018
#ifdef PF_DEBUG_BCAST_PREVAR
3019
                                MesPrint(">> Broadcast PreVar: %s = \"%s\"", PreVar[index].name, value);
3020
#endif
3021
                        }
3022
/*
3023
                        #] Master : 
3024
*/
3025
        }
3026
        if ( PF_LongMultiBroadcast() ) return -1;
20✔
3027
        if ( PF.me != MASTER ) {
20✔
3028
/*
3029
                        #[ Slave :
3030
*/
3031
                int i, nredefs;
15✔
3032
                /* Unpack the number of redefined preprocessor variables. */
3033
                PF_LongMultiUnpack(&nredefs, 1, PF_INT);
15✔
3034
                if ( nredefs > 0 ) {
15✔
3035
                        /* Then unpack each variable and put it. */
3036
                        for ( i = 0; i < nredefs; i++ ) {
18✔
3037
                                WORD index;
9✔
3038
                                int bytes;
9✔
3039
                                UBYTE *value;
9✔
3040
                                PF_LongMultiUnpack(&index, 1, PF_WORD);
9✔
3041
                                PF_LongMultiUnpack(&bytes, 1, PF_INT);
9✔
3042
                                VectorReserve(prevarbuf, bytes + 1);
9✔
3043
                                value = VectorPtr(prevarbuf);
9✔
3044
                                PF_LongMultiUnpack(value, bytes, PF_BYTE);
9✔
3045
                                value[bytes] = '\0';  /* The null terminator is needed. */
9✔
3046
                                PutPreVar(PreVar[index].name, value, NULL, 1);
9✔
3047
                        }
3048
                }
3049
/*
3050
                        #] Slave : 
3051
*/
3052
        }
3053
        return 0;
3054
}
3055

3056
/*
3057
                 #] PF_BroadcastRedefinedPreVars : 
3058
          #] Synchronization of redefined preprocessor variables : 
3059
          #[ Preprocessor Inside instruction :
3060
                 #[ Variables :
3061
*/
3062

3063
/* Saved values of AC.RhsExprInModuleFlag, PotModdollars and AC.pfirstnum. */
3064
static WORD oldRhsExprInModuleFlag;
3065
static Vector(WORD, oldPotModdollars);
3066
static Vector(WORD, oldpfirstnum);
3067

3068
/*
3069
                 #] Variables : 
3070
                 #[ PF_StoreInsideInfo :
3071
*/
3072

3073
/*
3074
 * Saves the current values of AC.RhsExprInModuleFlag, PotModdollars
3075
 * and AC.pfirstnum.
3076
 *
3077
 * Called by DoInside().
3078
 *
3079
 * @return  0  if OK, nonzero on error.
3080
 */
3081
int PF_StoreInsideInfo(void)
40✔
3082
{
3083
        int i;
40✔
3084
        oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
40✔
3085
        VectorClear(oldPotModdollars);
40✔
3086
        for ( i = 0; i < NumPotModdollars; i++ )
40✔
3087
                VectorPushBack(oldPotModdollars, PotModdollars[i]);
×
3088
        VectorClear(oldpfirstnum);
40✔
3089
        for ( i = 0; i < AC.numpfirstnum; i++ )
40✔
3090
                VectorPushBack(oldpfirstnum, AC.pfirstnum[i]);
×
3091
        return 0;
40✔
3092
}
3093

3094
/*
3095
                 #] PF_StoreInsideInfo : 
3096
                 #[ PF_RestoreInsideInfo :
3097
*/
3098

3099
/*
3100
 * Restores the saved values of AC.RhsExprInModuleFlag, PotModdollars
3101
 * and AC.pfirstnum.
3102
 *
3103
 * Called by DoEndInside().
3104
 *
3105
 * @return  0  if OK, nonzero on error.
3106
 */
3107
int PF_RestoreInsideInfo(void)
40✔
3108
{
3109
        int i;
40✔
3110
        AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
40✔
3111
        NumPotModdollars = VectorSize(oldPotModdollars);
40✔
3112
        for ( i = 0; i < NumPotModdollars; i++ )
40✔
3113
                PotModdollars[i] = VectorPtr(oldPotModdollars)[i];
×
3114
        AC.numpfirstnum = VectorSize(oldpfirstnum);
40✔
3115
        for ( i = 0; i < AC.numpfirstnum; i++ )
40✔
3116
                AC.pfirstnum[i] = VectorPtr(oldpfirstnum)[i];
×
3117
        return 0;
40✔
3118
}
3119

3120
/*
3121
                 #] PF_RestoreInsideInfo : 
3122
          #] Preprocessor Inside instruction : 
3123
          #[ PF_BroadcastCBuf :
3124
*/
3125

3126
/**
3127
 * Broadcasts a compiler buffer specified by \a bufnum from the master
3128
 * to the all slaves.
3129
 *
3130
 * @param  bufnum  The index of the compiler buffer to be broadcast.
3131
 * @return         0 if OK, nonzero on error.
3132
 */
3133
int PF_BroadcastCBuf(int bufnum)
28✔
3134
{
3135
        CBUF *C = cbuf + bufnum;
28✔
3136
        int i;
28✔
3137
        LONG l;
28✔
3138
        if ( PF.me == MASTER ) {
28✔
3139
/*
3140
                 #[ Master :
3141
*/
3142
                PF_PrepareLongMultiPack();
7✔
3143
                /* Pack CBUF struct except pointers. */
3144
                PF_LongMultiPack(&C->BufferSize, 1, PF_LONG);
7✔
3145
                PF_LongMultiPack(&C->numlhs, 1, PF_INT);
7✔
3146
                PF_LongMultiPack(&C->numrhs, 1, PF_INT);
7✔
3147
                PF_LongMultiPack(&C->maxlhs, 1, PF_INT);
7✔
3148
                PF_LongMultiPack(&C->maxrhs, 1, PF_INT);
7✔
3149
                PF_LongMultiPack(&C->mnumlhs, 1, PF_INT);
7✔
3150
                PF_LongMultiPack(&C->mnumrhs, 1, PF_INT);
7✔
3151
                PF_LongMultiPack(&C->numtree, 1, PF_INT);
7✔
3152
                PF_LongMultiPack(&C->rootnum, 1, PF_INT);
7✔
3153
                PF_LongMultiPack(&C->MaxTreeSize, 1, PF_INT);
7✔
3154
                /* Now pointers. Pointer, lhs and rhs are packed as offsets. We don't pack Top. */
3155
                l = C->Pointer - C->Buffer;
7✔
3156
                PF_LongMultiPack(&l, 1, PF_LONG);
7✔
3157
                PF_LongMultiPack(C->Buffer, l, PF_WORD);
7✔
3158
                for ( i = 0; i < C->numlhs + 1; i++ ) {
21✔
3159
                        l = C->lhs[i] - C->Buffer;
7✔
3160
                        PF_LongMultiPack(&l, 1, PF_LONG);
7✔
3161
                }
3162
                for ( i = 0; i < C->numrhs + 1; i++ ) {
744✔
3163
                        l = C->rhs[i] - C->Buffer;
737✔
3164
                        PF_LongMultiPack(&l, 1, PF_LONG);
737✔
3165
                }
3166
                PF_LongMultiPack(C->CanCommu, C->numrhs + 1, PF_LONG);
7✔
3167
                PF_LongMultiPack(C->NumTerms, C->numrhs + 1, PF_LONG);
7✔
3168
                PF_LongMultiPack(C->numdum, C->numrhs + 1, PF_WORD);
7✔
3169
                PF_LongMultiPack(C->dimension, C->numrhs + 1, PF_WORD);
7✔
3170
                if ( C->MaxTreeSize > 0 )
7✔
3171
                        PF_LongMultiPack(C->boomlijst, (C->numtree + 1) * (sizeof(COMPTREE) / sizeof(int)), PF_INT);
7✔
3172
#ifdef PF_DEBUG_BCAST_CBUF
3173
                MesPrint(">> Broadcast CBuf %d", bufnum);
3174
#endif
3175
/*
3176
                 #] Master : 
3177
*/
3178
        }
3179
        if ( PF_LongMultiBroadcast() ) return -1;
28✔
3180
        if ( PF.me != MASTER ) {
28✔
3181
/*
3182
                 #[ Slave :
3183
*/
3184
                /* First, free already allocated buffers. */
3185
                finishcbuf(bufnum);
21✔
3186
                /* Unpack CBUF struct except pointers. */
3187
                PF_LongMultiUnpack(&C->BufferSize, 1, PF_LONG);
21✔
3188
                PF_LongMultiUnpack(&C->numlhs, 1, PF_INT);
21✔
3189
                PF_LongMultiUnpack(&C->numrhs, 1, PF_INT);
21✔
3190
                PF_LongMultiUnpack(&C->maxlhs, 1, PF_INT);
21✔
3191
                PF_LongMultiUnpack(&C->maxrhs, 1, PF_INT);
21✔
3192
                PF_LongMultiUnpack(&C->mnumlhs, 1, PF_INT);
21✔
3193
                PF_LongMultiUnpack(&C->mnumrhs, 1, PF_INT);
21✔
3194
                PF_LongMultiUnpack(&C->numtree, 1, PF_INT);
21✔
3195
                PF_LongMultiUnpack(&C->rootnum, 1, PF_INT);
21✔
3196
                PF_LongMultiUnpack(&C->MaxTreeSize, 1, PF_INT);
21✔
3197
                /* Allocate new buffers. */
3198
                C->Buffer = (WORD *)Malloc1(C->BufferSize * sizeof(WORD), "compiler buffer");
21✔
3199
                C->Top = C->Buffer + C->BufferSize;
21✔
3200
                C->lhs = (WORD **)Malloc1(C->maxlhs * sizeof(WORD *), "compiler buffer");
21✔
3201
                C->rhs = (WORD **)Malloc1(C->maxrhs * (sizeof(WORD *) + 2 * sizeof(LONG) + 2 * sizeof(WORD)), "compiler buffer");
21✔
3202
                C->CanCommu = (LONG *)(C->rhs + C->maxrhs);
21✔
3203
                C->NumTerms = C->CanCommu + C->maxrhs;
21✔
3204
                C->numdum = (WORD *)(C->NumTerms + C->maxrhs);
21✔
3205
                C->dimension = C->numdum + C->maxrhs;
21✔
3206
                if ( C->MaxTreeSize > 0 )
21✔
3207
                        C->boomlijst = (COMPTREE *)Malloc1(C->MaxTreeSize * sizeof(COMPTREE), "compiler buffer");
21✔
3208
                /* Unpack buffers. */
3209
                PF_LongMultiUnpack(&l, 1, PF_LONG);
21✔
3210
                PF_LongMultiUnpack(C->Buffer, l, PF_WORD);
21✔
3211
                C->Pointer = C->Buffer + l;
21✔
3212
                for ( i = 0; i < C->numlhs + 1; i++ ) {
42✔
3213
                        PF_LongMultiUnpack(&l, 1, PF_LONG);
21✔
3214
                        C->lhs[i] = C->Buffer + l;
21✔
3215
                }
3216
                for ( i = 0; i < C->numrhs + 1; i++ ) {
2,232✔
3217
                        PF_LongMultiUnpack(&l, 1, PF_LONG);
2,211✔
3218
                        C->rhs[i] = C->Buffer + l;
2,211✔
3219
                }
3220
                PF_LongMultiUnpack(C->CanCommu, C->numrhs + 1, PF_LONG);
21✔
3221
                PF_LongMultiUnpack(C->NumTerms, C->numrhs + 1, PF_LONG);
21✔
3222
                PF_LongMultiUnpack(C->numdum, C->numrhs + 1, PF_WORD);
21✔
3223
                PF_LongMultiUnpack(C->dimension, C->numrhs + 1, PF_WORD);
21✔
3224
                if ( C->MaxTreeSize > 0 )
21✔
3225
                        PF_LongMultiUnpack(C->boomlijst, (C->numtree + 1) * (sizeof(COMPTREE) / sizeof(int)), PF_INT);
21✔
3226
/*
3227
                 #] Slave : 
3228
*/
3229
        }
3230
        return 0;
3231
}
3232

3233
/*
3234
          #] PF_BroadcastCBuf : 
3235
          #[ PF_BroadcastExpFlags :
3236
*/
3237

3238
/**
3239
 * Broadcasts AR.expflags and several properties of each expression,
3240
 * e.g., e->vflags, from the master to all slaves.
3241
 *
3242
 * @return 0 if OK, nonzero on error.
3243
 */
3244
int PF_BroadcastExpFlags(void)
1,917✔
3245
{
3246
        WORD i;
1,917✔
3247
        EXPRESSIONS e;
1,917✔
3248
        if ( PF.me == MASTER ) {
1,917✔
3249
/*
3250
                 #[ Master :
3251
*/
3252
                PF_PrepareLongMultiPack();
480✔
3253
                PF_LongMultiPack(&AR.expflags, 1, PF_WORD);
480✔
3254
                for ( i = 0; i < NumExpressions; i++ ) {
3,505✔
3255
                        e = &Expressions[i];
2,545✔
3256
                        PF_LongMultiPack(&e->counter,    1, PF_WORD);
2,545✔
3257
                        PF_LongMultiPack(&e->vflags,     1, PF_WORD);
2,545✔
3258
                        PF_LongMultiPack(&e->uflags,     1, PF_WORD);
2,545✔
3259
                        PF_LongMultiPack(&e->numdummies, 1, PF_WORD);
2,545✔
3260
                        PF_LongMultiPack(&e->numfactors, 1, PF_WORD);
2,545✔
3261
#ifdef PF_DEBUG_BCAST_EXPRFLAGS
3262
                        MesPrint(">> Broadcast ExprFlags: %s", AC.exprnames->namebuffer + e->name);
3263
#endif
3264
                }
3265
/*
3266
                 #] Master : 
3267
*/
3268
        }
3269
        if ( PF_LongMultiBroadcast() ) return -1;
1,917✔
3270
        if ( PF.me != MASTER ) {
1,917✔
3271
/*
3272
                 #[ Slave :
3273
*/
3274
                PF_LongMultiUnpack(&AR.expflags, 1, PF_WORD);
1,437✔
3275
                for ( i = 0; i < NumExpressions; i++ ) {
10,509✔
3276
                        e = &Expressions[i];
7,635✔
3277
                        PF_LongMultiUnpack(&e->counter,    1, PF_WORD);
7,635✔
3278
                        PF_LongMultiUnpack(&e->vflags,     1, PF_WORD);
7,635✔
3279
                        PF_LongMultiUnpack(&e->uflags,     1, PF_WORD);
7,635✔
3280
                        PF_LongMultiUnpack(&e->numdummies, 1, PF_WORD);
7,635✔
3281
                        PF_LongMultiUnpack(&e->numfactors, 1, PF_WORD);
7,635✔
3282
                }
3283
/*
3284
                 #] Slave : 
3285
*/
3286
        }
3287
        return 0;
3288
}
3289

3290
/*
3291
          #] PF_BroadcastExpFlags : 
3292
          #[ PF_SetScratch :
3293
*/
3294

3295
/**
3296
 * Same as SetScratch() except it always fills the buffer from the given position.
3297
 *
3298
 * @param  f         the file handle.
3299
 * @param  position  the position to be loaded into the buffer.
3300
 */
3301
static void PF_SetScratch(FILEHANDLE *f,POSITION *position)
260✔
3302
{
3303
        if(
260✔
3304
                        ( f->handle >= 0) && ISGEPOS(*position,f->POposition) &&
260✔
3305
                        ( ISGEPOSINC(*position,f->POposition,(f->POfull-f->PObuffer)*sizeof(WORD)) ==0 )
×
3306
                )/*position is inside the buffer! SetScratch() will do nothing.*/
3307
                        f->POfull=f->PObuffer;/*force SetScratch() to re-read the position from the beginning:*/
×
3308
        SetScratch(f,position);
260✔
3309
}
260✔
3310

3311
/*
3312
          #] PF_SetScratch : 
3313
          #[ PF_pushScratch :
3314
*/
3315

3316
/**
3317
 * Flushes a scratch file.
3318
 *
3319
 * @param  f  the scratch file to be flushed.
3320
 * @return    0 if OK, nonzero on error.
3321
 */
3322
static int PF_pushScratch(FILEHANDLE *f)
×
3323
{
3324
        LONG size,RetCode;
×
3325
        if ( f->handle < 0){
×
3326
                /*Create the file*/
3327
                if ( ( RetCode = CreateFile(f->name) ) >= 0 ) {
×
3328
                        f->handle = (WORD)RetCode;
×
3329
                        PUTZERO(f->filesize);
×
3330
                        PUTZERO(f->POposition);
×
3331
                }
3332
                else{
3333
                        MesPrint("Cannot create scratch file %s",f->name);
×
3334
                        return(-1);
×
3335
                }
3336
        }/*if ( f->handle < 0)*/
3337
        size = (f->POfill-f->PObuffer)*sizeof(WORD);
×
3338
        if( size > 0 ){
×
3339
                SeekFile(f->handle,&(f->POposition),SEEK_SET);
×
3340
                if ( WriteFile(f->handle,(UBYTE *)(f->PObuffer),size) != size ){
×
3341
                        MesPrint("Error while writing to disk. Disk full?");
×
3342
                        return(-1);
×
3343
                }
3344
                ADDPOS(f->filesize,size);
×
3345
                ADDPOS(f->POposition,size);
×
3346
                f->POfill = f->POfull=f->PObuffer;
×
3347
        }/*if( size > 0 )*/
3348
        return(0);
3349
}
3350

3351
/*
3352
          #] PF_pushScratch : 
3353
          #[ Broadcasting RHS expressions :
3354
                 #[ PF_WalkThroughExprMaster :
3355
        Returns <=0 if the expression is ready, or dl+1;
3356
*/
3357

3358
static int PF_WalkThroughExprMaster(FILEHANDLE *curfile, int dl)
11,217✔
3359
{
3360
        LONG l=0;
11,217✔
3361
        for(;;){
2,044,700✔
3362
                if(curfile->POfull-curfile->POfill < dl){
2,044,700✔
3363
                        POSITION pos;
×
3364
                        SeekScratch(curfile,&pos);
×
3365
                        PF_SetScratch(curfile,&pos);
×
3366
                }/*if(curfile->POfull-curfile->POfill < dl)*/
3367
                curfile->POfill+=dl;
2,044,700✔
3368
                l+=dl;
2,044,700✔
3369
                if( l >= PF.exprbufsize){
2,044,700✔
3370
                        if( l == PF.exprbufsize){
10,910✔
3371
                                if( *(curfile->POfill) == 0)/*expression is ready*/
3✔
3372
                                        return(0);
3373
                                }
3374
                        l-=PF.exprbufsize;
10,910✔
3375
                        curfile->POfill-=l;
10,910✔
3376
                        return l+1;
10,910✔
3377
                }
3378

3379
                dl=*(curfile->POfill);
2,033,780✔
3380
                if(dl == 0)
2,033,780✔
3381
                        return l-PF.exprbufsize;
307✔
3382

3383
                if(dl<0){/*compressed term*/
2,033,480✔
3384
                        if(curfile->POfull-curfile->POfill < 1){
5,231✔
3385
                                POSITION pos;
×
3386
                                SeekScratch(curfile,&pos);
×
3387
                                PF_SetScratch(curfile,&pos);
×
3388
                        }/*if(curfile->POfull-curfile->POfill < 1)*/
3389
                        dl=*(curfile->POfill+1)+2;
5,231✔
3390
                }/*if(*(curfile->POfill)<0)*/
3391
        }/*for(;;)*/
3392
}
3393

3394
/*
3395
                 #] PF_WalkThroughExprMaster : 
3396
                 #[ PF_WalkThroughExprSlave :
3397
        Returns <=0 if the expression is ready, or dl+1;
3398
*/
3399

3400
static int PF_WalkThroughExprSlave(FILEHANDLE *curfile, LONG *counter, int dl)
33,651✔
3401
{
3402
        LONG l=0;
33,651✔
3403
        for(;;){
6,134,080✔
3404
                if(curfile->POstop-curfile->POfill < dl){
6,134,080✔
3405
                        if(PF_pushScratch(curfile))
×
3406
                                return(-PF.exprbufsize-1);
×
3407
                }
3408
                curfile->POfill+=dl;
6,134,080✔
3409
                curfile->POfull=curfile->POfill;
6,134,080✔
3410
                l+=dl;
6,134,080✔
3411
                if( l >= PF.exprbufsize){
6,134,080✔
3412
                        if( l == PF.exprbufsize){
32,730✔
3413
                                /*
3414
                                 * This access is valid because PF.exprbufsize+1 WORDs are
3415
                                 * broadcasted, this shortcut is not mandatory though. (TU 15 Sep 2011)
3416
                                 */
3417
                                if( *(curfile->POfill) == 0)/*expression is ready*/
9✔
3418
                                        return(0);
3419
                                }
3420
                        l-=PF.exprbufsize;
32,730✔
3421
                        curfile->POfill-=l;
32,730✔
3422
                        curfile->POfull=curfile->POfill;
32,730✔
3423
                        return l+1;
32,730✔
3424
                }
3425

3426
                dl=*(curfile->POfill);
6,101,360✔
3427
                if(dl == 0)
6,101,360✔
3428
                        return l-PF.exprbufsize;
921✔
3429
                (*counter)++;
6,100,430✔
3430
                if(dl<0){/*compressed term*/
6,100,430✔
3431
                        if(curfile->POstop-curfile->POfill < 1){
15,693✔
3432
                                if(PF_pushScratch(curfile))
×
3433
                                        return(-PF.exprbufsize-1);
×
3434
                        }
3435
                        /*
3436
                         * This access is always valid because PF.exprbufsize+1 WORDs are
3437
                         * broadcasted. (TU 15 Sep 2011)
3438
                         */
3439
                        dl=*(curfile->POfill+1)+2;
15,693✔
3440
                }/*if(*(curfile->POfill)<0)*/
3441
        }/*for(;;)*/
3442
}
3443

3444
/*
3445
                 #] PF_WalkThroughExprSlave : 
3446
                 #[ PF_rhsBCastMaster :
3447
*/
3448

3449
/**
3450
 * On the master, broadcasts an expression to the all slaves.
3451
 *
3452
 * @param  curfile  the scratch file in which the expression is stored.
3453
 * @param  e        the expression to be broadcasted.
3454
 * @return          0 if OK, nonzero on error.
3455
 */
3456
static int PF_rhsBCastMaster(FILEHANDLE *curfile, EXPRESSIONS e)
307✔
3457
{
3458
        LONG l=1;/*PF_WalkThroughExpr returns length + 1*/
307✔
3459
        SetScratch(curfile,&(e->onfile));
307✔
3460
        do{
11,217✔
3461
                /*
3462
                 * We need to broadcast PF.exprbufsize+1 WORDs because PF_WalkThroughExprSlave
3463
                 * may access to an additional 1 WORD. It is better to rewrite the routines
3464
                 * in such a way as to broadcast only PF.exprbufsize WORDs. (TU 15 Sep 2011)
3465
                 */
3466
                if ( curfile->POfull - curfile->POfill < PF.exprbufsize + 1 ) {
11,217✔
3467
                        POSITION pos;
260✔
3468
                        SeekScratch(curfile,&pos);
260✔
3469
                        PF_SetScratch(curfile,&pos);
260✔
3470
                }
3471
                if ( PF_Bcast(curfile->POfill, (PF.exprbufsize + 1) * sizeof(WORD)) )
11,217✔
3472
                        return -1;
3473
                l=PF_WalkThroughExprMaster(curfile,l-1);
11,217✔
3474
        }while(l>0);
11,217✔
3475
        if(l<0)/*The tail is extra, decrease POfill*/
307✔
3476
                curfile->POfill-=l;
307✔
3477
        return(0);
3478
}
3479

3480
/*
3481
                 #] PF_rhsBCastMaster : 
3482
                 #[ PF_rhsBCastSlave :
3483
*/
3484

3485
/**
3486
 * On the slave, receives an expression broadcasted from the master.
3487
 *
3488
 * @param  curfile  the scratch file to store the broadcasted expression
3489
 *                  (AR.infile or AR.hidefile).
3490
 * @param  e        the expression to be broadcasted.
3491
 * @return          0 if OK, nonzero on error.
3492
 */
3493
static int PF_rhsBCastSlave(FILEHANDLE *curfile, EXPRESSIONS e)
921✔
3494
{
3495
        LONG l=1;/*PF_WalkThroughExpr returns length + 1*/
921✔
3496
        LONG counter = 0;
921✔
3497
        do{
33,651✔
3498
                /*
3499
                 * We need to broadcast PF.exprbufsize+1 WORDs because PF_WalkThroughExprSlave
3500
                 * may access to an additional 1 WORD. It is better to rewrite the routines
3501
                 * in such a way as to broadcast only PF.exprbufsize WORDs. (TU 15 Sep 2011)
3502
                 */
3503
                if ( curfile->POstop - curfile->POfill < PF.exprbufsize + 1 ) {
33,651✔
3504
                        if(PF_pushScratch(curfile))
×
3505
                                return(-1);
3506
                }
3507
                if ( PF_Bcast(curfile->POfill, (PF.exprbufsize + 1) * sizeof(WORD)) )
33,651✔
3508
                        return(-1);
3509
                l = PF_WalkThroughExprSlave(curfile, &counter, l - 1);
33,651✔
3510
        }while(l>0);
33,651✔
3511
        if(l<0){/*The tail is extra, decrease POfill*/
921✔
3512
                if(l<-PF.exprbufsize)/*error due to a PF_pushScratch() failure */
921✔
3513
                        return(-1);
3514
                curfile->POfill-=l;
921✔
3515
        }
3516
        if ( curfile->handle >= 0 ) {
921✔
3517
                if ( PF_pushScratch(curfile) ) return -1;
×
3518
        }
3519
        curfile->POfull=curfile->POfill;
921✔
3520
        if ( curfile != AR.hidefile ) AR.InInBuf = curfile->POfull-curfile->PObuffer;
921✔
3521
        else                          AR.InHiBuf = curfile->POfull-curfile->PObuffer;
36✔
3522
        CHECK(counter == e->counter + 1);  /* The first term is the prototype. */
921✔
3523
        return(0);
3524
}
3525

3526
/*
3527
                 #] PF_rhsBCastSlave : 
3528
                 #[ PF_BroadcastExpr :
3529
*/
3530

3531
/**
3532
 * Broadcasts an expression from the master to the all slaves.
3533
 *
3534
 * @param  e     The expression to be broadcast.
3535
 * @param  file  The file in which the expression is sitting.
3536
 * @return       0 if OK, nonzero on error.
3537
 */
3538
int PF_BroadcastExpr(EXPRESSIONS e, FILEHANDLE *file)
1,228✔
3539
{
3540
        if ( PF.me == MASTER ) {
1,228✔
3541
                if ( PF_rhsBCastMaster(file, e) ) return -1;
307✔
3542
#ifdef PF_DEBUG_BCAST_RHSEXPR
3543
                MesPrint(">> Broadcast RhsExpr: %s", AC.exprnames->namebuffer + e->name);
3544
#endif
3545
        }
3546
        else {
3547
                POSITION pos;
921✔
3548
                SetEndHScratch(file, &pos);
921✔
3549
                e->onfile = pos;
921✔
3550
                if ( PF_rhsBCastSlave(file, e) ) return -1;
921✔
3551
        }
3552
        return 0;
3553
}
3554

3555
/*
3556
                 #] PF_BroadcastExpr : 
3557
                 #[ PF_BroadcastRHS :
3558
*/
3559

3560
/**
3561
 * Broadcasts expressions appearing in the right-hand side from
3562
 * the master to the all slaves.
3563
 *
3564
 * @return  0 if OK, nonzero on error.
3565
 */
3566
int PF_BroadcastRHS(void)
196✔
3567
{
3568
        int i;
196✔
3569
        for ( i = 0; i < NumExpressions; i++ ) {
2,508✔
3570
                EXPRESSIONS e = &Expressions[i];
2,312✔
3571
                if ( !(e->vflags & ISINRHS) ) continue;
2,312✔
3572
                switch ( e->status ) {
1,196✔
3573
                        case LOCALEXPRESSION:
1,148✔
3574
                        case SKIPLEXPRESSION:
3575
                        case DROPLEXPRESSION:
3576
                        case GLOBALEXPRESSION:
3577
                        case SKIPGEXPRESSION:
3578
                        case DROPGEXPRESSION:
3579
                        case HIDELEXPRESSION:
3580
                        case HIDEGEXPRESSION:
3581
                        case INTOHIDELEXPRESSION:
3582
                        case INTOHIDEGEXPRESSION:
3583
                                if ( PF_BroadcastExpr(e, AR.infile) ) return -1;
1,148✔
3584
                                break;
3585
                        case HIDDENLEXPRESSION:
48✔
3586
                        case HIDDENGEXPRESSION:
3587
                        case DROPHLEXPRESSION:
3588
                        case DROPHGEXPRESSION:
3589
                        case UNHIDELEXPRESSION:
3590
                        case UNHIDEGEXPRESSION:
3591
                                if ( PF_BroadcastExpr(e, AR.hidefile) ) return -1;
48✔
3592
                                break;
3593
                }
3594
        }
2,312✔
3595
        if ( PF.me != MASTER )
196✔
3596
                UpdatePositions();
147✔
3597
        return 0;
3598
}
3599

3600
/*
3601
                 #] PF_BroadcastRHS : 
3602
          #] Broadcasting RHS expressions : 
3603
          #[ InParallel mode :
3604
                 #[ PF_InParallelProcessor :
3605
*/
3606

3607
/**
3608
 * Processes expressions in the InParallel mode, i.e.,
3609
 * dividing expressions marked by partodo over the slaves.
3610
 *
3611
 * @return  0 if OK, nonzero on error.
3612
 */
3613
int PF_InParallelProcessor(void)
4✔
3614
{
3615
        GETIDENTITY
3616
        int i, next,tag;
4✔
3617
        EXPRESSIONS e;
4✔
3618
        /*
3619
         * Skip expressions with zero terms. All the master and slaves need to
3620
         * change the "partodo" flag.
3621
         */
3622
        if ( PF.numtasks >= 3 ) {
4✔
3623
                for ( i = 0; i < NumExpressions; i++ ) {
8✔
3624
                        e = Expressions + i;
4✔
3625
                        if ( e->partodo > 0 && e->counter == 0 ) {
4✔
3626
                                e->partodo = 0;
×
3627
                        }
3628
                }
3629
        }
3630
        if(PF.me == MASTER){
4✔
3631
                if ( PF.numtasks >= 3 ) {
1✔
3632
                        partodoexr = (WORD*)Malloc1(sizeof(WORD)*(PF.numtasks+1),"PF_InParallelProcessor");
1✔
3633
                        for ( i = 0; i < NumExpressions; i++ ) {
2✔
3634
                                e = Expressions+i;
1✔
3635
                                if ( e->partodo <= 0 ) continue;
1✔
3636
                                switch(e->status){
1✔
3637
                                        case LOCALEXPRESSION:
1✔
3638
                                        case GLOBALEXPRESSION:
3639
                                        case UNHIDELEXPRESSION:
3640
                                        case UNHIDEGEXPRESSION:
3641
                                        case INTOHIDELEXPRESSION:
3642
                                        case INTOHIDEGEXPRESSION:
3643
                                                tag=PF_ANY_SOURCE;
1✔
3644
                                                next=PF_Wait4SlaveIP(&tag);
1✔
3645
                                                if(next<0)
1✔
3646
                                                        return(-1);
3647
                                                if(tag == PF_DATA_MSGTAG){
1✔
3648
                                                        PF_Statistics(PF_stats,0);
×
3649
                                                        if(PF_Slave2MasterIP(next))
×
3650
                                                                return(-1);
3651
                                                }
3652
                                                if(PF_Master2SlaveIP(next,e))
1✔
3653
                                                        return(-1);
3654
                                                partodoexr[next]=i;
1✔
3655
                                                break;
1✔
3656
                                        default:
×
3657
                                                e->partodo = 0;
×
3658
                                                continue;
×
3659
                                }/*switch(e->status)*/
3660
                        }/*for ( i = 0; i < NumExpressions; i++ )*/
3661
                        /*Here some slaves are working, other are waiting on PF_Send.
3662
                                Wait all of them.*/
3663
                        /*At this point no new slaves may be launched so PF_WaitAllSlaves()
3664
                                does not modify partodoexr[].*/
3665
                        if(PF_WaitAllSlaves())
1✔
3666
                                return(-1);
3667
                        /**/
3668
                        if ( AC.CollectFun ) AR.DeferFlag = 0;
1✔
3669
                        if(partodoexr){
1✔
3670
                                M_free(partodoexr,"PF_InParallelProcessor");
1✔
3671
                                partodoexr=NULL;
1✔
3672
                        }/*if(partodoexr)*/
3673
                }/*if ( PF.numtasks >= 3 ) */
3674
                else {
3675
                        for ( i = 0; i < NumExpressions; i++ ) {
×
3676
                                Expressions[i].partodo = 0;
×
3677
                        }
3678
                }
3679
                return(0);
1✔
3680
        }/*if(PF.me == MASTER)*/
3681
        /*Slave:*/
3682
        if(PF_Wait4MasterIP(PF_EMPTY_MSGTAG))
3✔
3683
                return(-1);
3684
        /*master is ready to listen to me*/
3685
        do{
4✔
3686
                WORD *oldwork= AT.WorkPointer;
4✔
3687
                tag=PF_ReadMaster();/*reads directly to its scratch!*/
4✔
3688
                if(tag<0)
4✔
3689
                        return(-1);
3690
                if(tag == PF_DATA_MSGTAG){
4✔
3691
                        oldwork = AT.WorkPointer;
1✔
3692

3693
                        /* For redefine statements. */
3694
                        if ( AC.numpfirstnum > 0 ) {
1✔
3695
                                int j;
3696
                                for ( j = 0; j < AC.numpfirstnum; j++ ) {
×
3697
                                        AC.inputnumbers[j] = -1;
×
3698
                                }
3699
                        }
3700

3701
                        if(PF_DoOneExpr())/*the processor*/
1✔
3702
                                return(-1);
3703
                        if(PF_Wait4MasterIP(PF_DATA_MSGTAG))
1✔
3704
                                return(-1);
3705
                        if(PF_Slave2MasterIP(PF.me))/*both master and slave*/
1✔
3706
                                return(-1);
3707
                        AT.WorkPointer=oldwork;
1✔
3708
                }/*if(tag == PF_DATA_MSGTAG)*/
3709
        }while(tag!=PF_EMPTY_MSGTAG);
4✔
3710
        PF.exprtodo=-1;
3✔
3711
        return(0);
3✔
3712
}/*PF_InParallelProcessor*/
3713

3714
/*
3715
                 #] PF_InParallelProcessor : 
3716
                 #[ PF_Wait4MasterIP :
3717
*/
3718

3719
static int PF_Wait4MasterIP(int tag)
4✔
3720
{
3721
        int follow = 0;
4✔
3722
        LONG cpu,space = 0;
4✔
3723

3724
        if(PF.log){
4✔
3725
                fprintf(stderr,"[%d] Starting to send to Master\n",PF.me);
×
3726
                fflush(stderr);
×
3727
        }
3728

3729
        PF_PreparePack();
4✔
3730
        cpu = TimeCPU(1);
4✔
3731
        PF_Pack(&cpu               ,1,PF_LONG);
4✔
3732
        PF_Pack(&space             ,1,PF_LONG);
4✔
3733
        PF_Pack(&PF_linterms       ,1,PF_LONG);
4✔
3734
        PF_Pack(&(AM.S0->GenTerms) ,1,PF_LONG);
4✔
3735
        PF_Pack(&(AM.S0->TermsLeft),1,PF_LONG);
4✔
3736
        PF_Pack(&follow            ,1,PF_INT );
4✔
3737

3738
        if(PF.log){
4✔
3739
                fprintf(stderr,"[%d] Now sending with tag = %d\n",PF.me,tag);
×
3740
                fflush(stderr);
×
3741
        }
3742

3743
        PF_Send(MASTER, tag);
4✔
3744

3745
        if(PF.log){
4✔
3746
                fprintf(stderr,"[%d] returning from send\n",PF.me);
×
3747
                fflush(stderr);
×
3748
        }
3749
        return(0);
4✔
3750
}
3751
/*
3752
                 #] PF_Wait4MasterIP : 
3753
                 #[ PF_DoOneExpr :
3754
*/
3755

3756
/**
3757
 * Processes an expression specified by PF.exprtodo.
3758
 *
3759
 * See also "case DOONEEXPRESSION" in RunThread().
3760
 *
3761
 * @return        0 if OK, nonzero on error.
3762
 */
3763
static int PF_DoOneExpr(void)/*the processor*/
1✔
3764
{
3765
                                GETIDENTITY
3766
                                EXPRESSIONS e;
1✔
3767
                                int i;
1✔
3768
                                WORD *term;
1✔
3769
                                POSITION position, outposition;
1✔
3770
                                FILEHANDLE *fi, *fout;
1✔
3771
                                LONG dd = 0;
1✔
3772
                                WORD oldBracketOn = AR.BracketOn;
1✔
3773
                                WORD *oldBrackBuf = AT.BrackBuf;
1✔
3774
                                WORD oldbracketindexflag = AT.bracketindexflag;
1✔
3775
                                e = Expressions + PF.exprtodo;
1✔
3776
                                i = PF.exprtodo;
1✔
3777
                                AR.CurExpr = i;
1✔
3778
                                AR.SortType = AC.SortType;
1✔
3779
                                AR.expchanged = 0;
1✔
3780
                                if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
1✔
3781
                                        AR.BracketOn = 1;
×
3782
                                        AT.BrackBuf = AM.BracketFactors;
×
3783
                                        AT.bracketindexflag = 1;
×
3784
                                }
3785

3786
                                position = AS.OldOnFile[i];
1✔
3787
                                if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION ) {
1✔
3788
                                        AR.GetFile = 2; fi = AR.hidefile;
×
3789
                                }
3790
                                else {
3791
                                        AR.GetFile = 0; fi = AR.infile;
1✔
3792
                                }
3793
/*
3794
                                PUTZERO(fi->POposition);
3795
                                if ( fi->handle >= 0 ) {
3796
                                        fi->POfill = fi->POfull = fi->PObuffer;
3797
                                }
3798
*/
3799
                                SetScratch(fi,&position);
1✔
3800
                                term = AT.WorkPointer;
1✔
3801
                                AR.CompressPointer = AR.CompressBuffer;
1✔
3802
                                AR.CompressPointer[0] = 0;
1✔
3803
                                AR.KeptInHold = 0;
1✔
3804
                                if ( GetTerm(BHEAD term) <= 0 ) {
1✔
3805
                                        MesPrint("Expression %d has problems in scratchfile",i);
×
3806
                                        Terminate(-1);
×
3807
                                }
3808
                                if ( AT.bracketindexflag > 0 ) OpenBracketIndex(i);
1✔
3809
                                term[3] = i;
1✔
3810
                                PUTZERO(outposition);
1✔
3811
                                fout = AR.outfile;
1✔
3812
                                fout->POfill = fout->POfull = fout->PObuffer;
1✔
3813
                                fout->POposition = outposition;
1✔
3814
                                if ( fout->handle >= 0 ) {
1✔
3815
                                        fout->POposition = outposition;
×
3816
                                }
3817
/*
3818
                                The next statement is needed because we need the system
3819
                                to believe that the expression is at position zero for
3820
                                the moment. In this worker, with no memory of other expressions,
3821
                                it is. This is needed for when a bracket index is made
3822
                                because there e->onfile is an offset. Afterwards, when the
3823
                                expression is written to its final location in the masters
3824
                                output e->onfile will get its real value.
3825
*/
3826
                                PUTZERO(e->onfile);
1✔
3827
                                if ( PutOut(BHEAD term,&outposition,fout,0) < 0 ) return -1;
1✔
3828

3829
                                AR.DeferFlag = AC.ComDefer;
1✔
3830

3831
/*                                AR.sLevel = AB[0]->R.sLevel;*/
3832
                                term = AT.WorkPointer;
1✔
3833
                                NewSort(BHEAD0);
1✔
3834
                                AR.MaxDum = AM.IndDum;
1✔
3835
                                AN.ninterms = 0;
1✔
3836
                                while ( GetTerm(BHEAD term) ) {
2✔
3837
                                  SeekScratch(fi,&position);
1✔
3838
                                  AN.ninterms++; dd = AN.deferskipped;
1✔
3839
                                  if ( ( e->vflags & ISFACTORIZED ) != 0 && term[1] == HAAKJE ) {
1✔
3840
                                          StoreTerm(BHEAD term);
×
3841
                                  }
3842
                                  else {
3843
                                  if ( AC.CollectFun && *term <= (AM.MaxTer/(2*(LONG)sizeof(WORD))) ) {
1✔
3844
                                        if ( GetMoreTerms(term) < 0 ) {
×
3845
                                          LowerSortLevel(); return(-1);
×
3846
                                        }
3847
                                    SeekScratch(fi,&position);
×
3848
                                  }
3849
                                  AT.WorkPointer = term + *term;
1✔
3850
                                  AN.RepPoint = AT.RepCount + 1;
1✔
3851
                                  if ( AR.DeferFlag ) {
1✔
3852
                                        AR.CurDum = AN.IndDum = Expressions[PF.exprtodo].numdummies;
×
3853
                                  }
3854
                                  else {
3855
                                        AN.IndDum = AM.IndDum;
1✔
3856
                                        AR.CurDum = ReNumber(BHEAD term);
1✔
3857
                                  }
3858
                                  if ( AC.SymChangeFlag ) MarkDirty(term,DIRTYSYMFLAG);
1✔
3859
                                  if ( AN.ncmod ) {
1✔
3860
                                        if ( ( AC.modmode & ALSOFUNARGS ) != 0 ) MarkDirty(term,DIRTYFLAG);
×
3861
                                        else if ( AR.PolyFun ) PolyFunDirty(BHEAD term);
×
3862
                                  }
3863
                                  else if ( AC.PolyRatFunChanged ) PolyFunDirty(BHEAD term);
1✔
3864
                                  if ( ( AR.PolyFunType == 2 ) && ( AC.PolyRatFunChanged == 0 )
1✔
3865
                                                && ( e->status == LOCALEXPRESSION || e->status == GLOBALEXPRESSION ) ) {
×
3866
                                                PolyFunClean(BHEAD term);
×
3867
                                  }
3868
                                  if ( Generator(BHEAD term,0) ) {
1✔
3869
                                        LowerSortLevel(); return(-1);
×
3870
                                  }
3871
                                  AN.ninterms += dd;
1✔
3872
                                  }
3873
                                  SetScratch(fi,&position);
1✔
3874
                                  if ( fi == AR.hidefile ) {
1✔
3875
                                        AR.InHiBuf = (fi->POfull-fi->PObuffer)
×
3876
                                                -DIFBASE(position,fi->POposition)/sizeof(WORD);
×
3877
                                  }
3878
                                  else {
3879
                                        AR.InInBuf = (fi->POfull-fi->PObuffer)
1✔
3880
                                                -DIFBASE(position,fi->POposition)/sizeof(WORD);
1✔
3881
                                  }
3882
                                }
3883
                                AN.ninterms += dd;
1✔
3884
                                if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) return(-1);
1✔
3885
                                e->numdummies = AR.MaxDum - AM.IndDum;
1✔
3886
                                AR.BracketOn = oldBracketOn;
1✔
3887
                                AT.BrackBuf = oldBrackBuf;
1✔
3888
                                if ( ( e->vflags & TOBEFACTORED ) != 0 )
1✔
3889
                                                poly_factorize_expression(e);
×
3890
                                else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
1✔
3891
                                 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
1✔
3892
                                                poly_unfactorize_expression(e);
×
3893
                                if ( AM.S0->TermsLeft )   e->vflags &= ~ISZERO;
1✔
3894
                                else                      e->vflags |= ISZERO;
×
3895
                                if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
1✔
3896
/*                                if ( AM.S0->TermsLeft ) AR.expflags |= ISZERO;
3897
                                if ( AR.expchanged )    AR.expflags |= ISUNMODIFIED;*/
3898
                                AR.GetFile = 0;
1✔
3899
                                AT.bracketindexflag = oldbracketindexflag;
1✔
3900

3901
                                fout->POfull = fout->POfill;
1✔
3902
        return(0);
1✔
3903
}
3904

3905
/*
3906
                 #] PF_DoOneExpr : 
3907
                 #[ PF_Slave2MasterIP :
3908
*/
3909

3910
typedef struct bufIPstruct {
3911
        LONG i;
3912
        struct ExPrEsSiOn e;
3913
} bufIPstruct_t;
3914

3915
static int PF_Slave2MasterIP(int src)/*both master and slave*/
2✔
3916
{
3917
        EXPRESSIONS e;
2✔
3918
        bufIPstruct_t exprData;
2✔
3919
        int i,l;
2✔
3920
        FILEHANDLE *fout=AR.outfile;
2✔
3921
        POSITION pos;
2✔
3922
        /*Here we know the length of data to send in advance:
3923
                slave has the only one expression in its scratch file, and it sends
3924
                this information to the master.*/
3925
        if(PF.me != MASTER){/*slave*/
2✔
3926
                e = Expressions + PF.exprtodo;
1✔
3927
                /*Fill in the expression data:*/
3928
                memcpy(&(exprData.e), e, sizeof(struct ExPrEsSiOn));
1✔
3929
                SeekScratch(fout,&pos);
1✔
3930
                exprData.i=BASEPOSITION(pos);
1✔
3931
                /*Send the metadata:*/
3932
                if(PF_RawSend(MASTER,&exprData,sizeof(bufIPstruct_t),0))
1✔
3933
                        return(-1);
3934
                i=exprData.i;
1✔
3935
                SETBASEPOSITION(pos,0);
1✔
3936
                do{
1✔
3937
                        int blen=PF.exprbufsize*sizeof(WORD);
1✔
3938
                        if(i<blen)
1✔
3939
                                blen=i;
1✔
3940
                        l=PF_SendChunkIP(fout,&pos, MASTER, blen);
1✔
3941
                        /*Here always l == blen!*/
3942
                        if(l<0)
1✔
3943
                                return(-1);
3944
                        ADDPOS(pos,l);
1✔
3945
                        i-=l;
1✔
3946
                }while(i>0);
1✔
3947
                if ( fout->handle >= 0 ) { /* Now get rid of the file */
1✔
3948
                        CloseFile(fout->handle);
×
3949
                        fout->handle = -1;
×
3950
                        remove(fout->name);
×
3951
                        PUTZERO(fout->POposition);
×
3952
                        PUTZERO(fout->filesize);
×
3953
                        fout->POfill = fout->POfull = fout->PObuffer;
×
3954
                }
3955
                /* Now handle redefined preprocessor variables. */
3956
                if ( AC.numpfirstnum > 0 ) {
1✔
3957
                        PF_PrepareLongSinglePack();
×
3958
                        PF_PackRedefinedPreVars();
×
3959
                        PF_LongSingleSend(MASTER, PF_MISC_MSGTAG);
×
3960
                }
3961
                return(0);
1✔
3962
        }/*if(PF.me != MASTER)*/
3963
        /*Master*/
3964
        /*partodoexr[src] is the number of expression.*/
3965
        e = Expressions +partodoexr[src];
1✔
3966
        /*Get metadata:*/
3967
        if (PF_RawRecv(&src, &exprData,sizeof(bufIPstruct_t),&i)!= sizeof(bufIPstruct_t))
1✔
3968
                return(-1);
3969
        /*Fill in the expression data:*/
3970
/*        memcpy(e, &(exprData.e), sizeof(struct ExPrEsSiOn)); */
3971
        e->counter    = exprData.e.counter;
1✔
3972
        e->vflags     = exprData.e.vflags;
1✔
3973
        e->uflags     = exprData.e.uflags;
1✔
3974
        e->numdummies = exprData.e.numdummies;
1✔
3975
        e->numfactors = exprData.e.numfactors;
1✔
3976
        if ( !(e->vflags & ISZERO) )       AR.expflags |= ISZERO;
1✔
3977
        if ( !(e->vflags & ISUNMODIFIED) ) AR.expflags |= ISUNMODIFIED;
1✔
3978
        SeekScratch(fout,&pos);
1✔
3979
        e->onfile = pos;
1✔
3980
        i=exprData.i;
1✔
3981
        while(i>0){
2✔
3982
                int blen=PF.exprbufsize*sizeof(WORD);
1✔
3983
                if(i<blen)
1✔
3984
                        blen=i;
1✔
3985
                l=PF_RecvChunkIP(fout,src,blen);
1✔
3986
                /*Here always l == blen!*/
3987
                if(l<0)
1✔
3988
                        return(-1);
3989
                i-=l;
1✔
3990
        }
3991
        /* Now handle redefined preprocessor variables. */
3992
        if ( AC.numpfirstnum > 0 ) {
1✔
3993
                PF_LongSingleReceive(src, PF_MISC_MSGTAG, NULL, NULL);
×
3994
                PF_UnpackRedefinedPreVars();
×
3995
        }
3996
        return(0);
3997
}
3998

3999
/*
4000
                 #] PF_Slave2MasterIP : 
4001
                 #[ PF_Master2SlaveIP :
4002
*/
4003

4004
static int PF_Master2SlaveIP(int dest, EXPRESSIONS e)
4✔
4005
{
4006
        bufIPstruct_t exprData;
4✔
4007
        FILEHANDLE *fi;
4✔
4008
        POSITION pos;
4✔
4009
        int l;
4✔
4010
        LONG ll=0,count=0;
4✔
4011
        WORD *t;
4✔
4012
        if(e==NULL){/*Say to the slave that no more job:*/
4✔
4013
                if(PF_RawSend(dest,&exprData,sizeof(bufIPstruct_t),PF_EMPTY_MSGTAG))
3✔
4014
                        return(-1);
4015
                return(0);
3✔
4016
        }
4017
        memcpy(&(exprData.e), e, sizeof(struct ExPrEsSiOn));
1✔
4018
        exprData.i=e-Expressions;
1✔
4019
        if ( AC.StatsFlag && AC.OldParallelStats ) {
1✔
4020
                MesPrint("");
×
4021
                MesPrint(" Sending expression %s to slave %d",EXPRNAME(exprData.i),dest);
×
4022
        }
4023
        if(PF_RawSend(dest,&exprData,sizeof(bufIPstruct_t),PF_DATA_MSGTAG))
1✔
4024
                return(-1);
4025
        if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION )
1✔
4026
                fi = AR.hidefile;
×
4027
        else
4028
                fi = AR.infile;
1✔
4029
        pos=e->onfile;
1✔
4030
        SetScratch(fi,&pos);
1✔
4031
        do{
1✔
4032
                l=PF_SendChunkIP(fi, &pos, dest, PF.exprbufsize*sizeof(WORD));
1✔
4033
                if(l<0)
1✔
4034
                        return(-1);
4035
                t=fi->PObuffer+ (DIFBASE(pos,fi->POposition))/sizeof(WORD);
1✔
4036
                ll=PF_WalkThrough(t,ll,l/sizeof(WORD),&count);
1✔
4037
                ADDPOS(pos,l);
1✔
4038
        }while(ll>-2);
1✔
4039
        return(0);
4040
}
4041

4042
/*
4043
                 #] PF_Master2SlaveIP : 
4044
                 #[ PF_ReadMaster :
4045
*/
4046

4047
static int PF_ReadMaster(void)/*reads directly to its scratch!*/
4✔
4048
{
4049
        bufIPstruct_t exprData;
4✔
4050
        int tag,m=MASTER;
4✔
4051
        EXPRESSIONS e;
4✔
4052
        FILEHANDLE *fi;
4✔
4053
        POSITION pos;
4✔
4054
        LONG count=0;
4✔
4055
        WORD *t;
4✔
4056
        LONG ll=0;
4✔
4057
        int l;
4✔
4058
        /*Get metadata:*/
4059
        if (PF_RawRecv(&m, &exprData,sizeof(bufIPstruct_t),&tag)!= sizeof(bufIPstruct_t))
4✔
4060
                return(-1);
4061

4062
        if(tag == PF_EMPTY_MSGTAG)/*No data, no job*/
4✔
4063
                return(tag);
4064

4065
        /*data expected, tag must be == PF_DATA_MSTAG!*/
4066
        PF.exprtodo=exprData.i;
1✔
4067
        e=Expressions + PF.exprtodo;
1✔
4068
        /*Fill in the expression data:*/
4069
/*        memcpy(e, &(exprData.e), sizeof(struct ExPrEsSiOn)); */
4070
        if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION )
1✔
4071
                fi = AR.hidefile;
×
4072
        else
4073
                fi = AR.infile;
1✔
4074
        SetEndHScratch(fi,&pos);
1✔
4075
        e->onfile=AS.OldOnFile[PF.exprtodo]=pos;
1✔
4076

4077
        do{
1✔
4078
                l=PF_RecvChunkIP(fi,MASTER,PF.exprbufsize*sizeof(WORD));
1✔
4079
                if(l<0)
1✔
4080
                        return(-1);
4081
                t=fi->POfull-l/sizeof(WORD);
1✔
4082
                ll=PF_WalkThrough(t,ll,l/sizeof(WORD),&count);
1✔
4083
        }while(ll>-2);
1✔
4084
        /*Now -ll-2 is the number of "extra" elements transferred from the master.*/
4085
        fi->POfull-=-ll-2;
1✔
4086
        fi->POfill=fi->POfull;
1✔
4087
        return(PF_DATA_MSGTAG);
1✔
4088
}
4089

4090
/*
4091
                 #] PF_ReadMaster : 
4092
                 #[ PF_SendChunkIP :
4093
        thesize is in bytes. Returns the number of sent bytes or <0 on error:
4094
*/
4095

4096
static int PF_SendChunkIP(FILEHANDLE *curfile, POSITION *position, int to, LONG thesize)
2✔
4097
{
4098
        LONG l=thesize;
2✔
4099
        if(
2✔
4100
                ISLESSPOS(*position,curfile->POposition) ||
2✔
4101
                ISGEPOSINC(*position,curfile->POposition,
2✔
4102
                ((curfile->POfull-curfile->PObuffer)*sizeof(WORD)-thesize) )
4103
        ){
4104
                if(curfile->handle< 0)
2✔
4105
                        l=(curfile->POfull-curfile->PObuffer)*sizeof(WORD) - (LONG)(position->p1);
2✔
4106
                else{
4107
                        PF_SetScratch(curfile,position);
×
4108
                        if(
×
4109
                                ISGEPOSINC(*position,curfile->POposition,
×
4110
                                ((curfile->POfull-curfile->PObuffer)*sizeof(WORD)-thesize) )
4111
                                )
4112
                        l=(curfile->POfull-curfile->PObuffer)*sizeof(WORD) - (LONG)position->p1;
×
4113
                }
4114
        }
4115
        /*Now we are able to sent l bytes from the
4116
                curfile->PObuffer[position-curfile->POposition]*/
4117
        if(PF_RawSend(to,curfile->PObuffer+ (DIFBASE(*position,curfile->POposition))/sizeof(WORD),l,0))
2✔
4118
                return(-1);
4119
        return(l);
2✔
4120
}
4121

4122
/*
4123
                 #] PF_SendChunkIP : 
4124
                 #[ PF_RecvChunkIP :
4125
        thesize is in bytes. Returns the number of sent bytes or <0 on error:
4126
*/
4127

4128
static int PF_RecvChunkIP(FILEHANDLE *curfile, int from, LONG thesize)
2✔
4129
{
4130
        LONG receivedBytes;
2✔
4131

4132
        if( (LONG)((curfile->POstop - curfile->POfull)*sizeof(WORD)) < thesize )
2✔
4133
                if(PF_pushScratch(curfile))
×
4134
                        return(-1);
4135
        /*Now there is enough space from curfile->POfill to curfile->POstop*/
4136
        {/*Block:*/
4137
                int tag=0;
2✔
4138
                receivedBytes=PF_RawRecv(&from,curfile->POfull,thesize,&tag);
2✔
4139
        }/*:Block*/
4140
        if(receivedBytes >= 0 ){
2✔
4141
                curfile->POfull+=receivedBytes/sizeof(WORD);
2✔
4142
                curfile->POfill=curfile->POfull;
2✔
4143
        }/*if(receivedBytes >= 0 )*/
4144
        return(receivedBytes);
2✔
4145
}
4146

4147
/*
4148
                 #] PF_RecvChunkIP : 
4149
                 #[ PF_WalkThrough :
4150
        Returns:
4151
        >=  0 -- initial offset,
4152
                -1 -- the first element of t contains the length of the tail of compressed term,
4153
        <= -2 -- -(d+2), where d is the number of extra transferred elements.
4154
        Expects:
4155
        l -- initial offset or -1,
4156
        chunk -- number of transferred elements (not bytes!)
4157
        *count -- incremented each time a new term is found
4158
*/
4159

4160
static int PF_WalkThrough(WORD *t, LONG l, LONG chunk, LONG *count)
2✔
4161
{
4162
        if(l<0) /*==-1!*/
2✔
4163
                l=(*t)+1;/*the first element of t contains the length of
×
4164
                                                the tail of compressed term*/
4165
        else{
4166
                if(l>=chunk)/*next term is out of the chunk*/
2✔
4167
                        return(l-chunk);
×
4168
                t+=l;
2✔
4169
                chunk-=l;/*note, l was less than chunk so chunk >0!*/
2✔
4170
                l=*t;
2✔
4171
        }
4172
        /*Main loop:*/
4173
        while(l!=0){
6✔
4174
                if(l>0){/*an offset to the next term*/
4✔
4175
                        if(l<chunk){
4✔
4176
                                t+=l;
4✔
4177
                                chunk-=l;/*note, l was less than chunk so chunk >0!*/
4✔
4178
                                l=*t;
4✔
4179
                                (*count)++;
4✔
4180
                        }/*if(l<chunk)*/
4181
                        else
4182
                                return(l-chunk);
×
4183
                }/*if(l>0)*/
4184
                else{ /* l<0 */
4185
                        if(chunk < 2)/*i.e., chunk == 1*/
×
4186
                                return(-1);/*the first WORD in the next chunk is length of the tail of the compressed term*/
4187
                        l=*(t+1)+2;/*+2 since
×
4188
                                        1. t points to the length field -1,
4189
                                        2. the size of a tail of compressed term is equal to the number of WORDs in this tail*/
4190
                }
4191
        }/*while(l!=0)*/
4192
        return(-1-chunk);/* -(2+(chunk-1)), chunk>0 ! */
2✔
4193
}
4194

4195
/*
4196
                 #] PF_WalkThrough : 
4197
          #] InParallel mode : 
4198
          #[ PF_SendFile :
4199
*/
4200

4201
#define PF_SNDFILEBUFSIZE 4096
4202

4203
/**
4204
 * Sends a file to the process specified by \a to.
4205
 *
4206
 * @param  to  the destination process number.
4207
 * @param  fd  the file to be sent.
4208
 * @return     the size of sent data in bytes, or -1 on error.
4209
 */
4210
int PF_SendFile(int to, FILE *fd)
×
4211
{
4212
        size_t len=0;
×
4213
        if(fd == NULL){
×
4214
                if(PF_RawSend(to,&to,sizeof(int),PF_EMPTY_MSGTAG))
×
4215
                        return(-1);
4216
                return(0);
×
4217
        }
4218
        for(;;){
×
4219
                char buf[PF_SNDFILEBUFSIZE];
×
4220
                size_t l;
×
4221
                l=fread(buf, 1, PF_SNDFILEBUFSIZE, fd);
×
4222
                len+=l;
×
4223
                if(l==PF_SNDFILEBUFSIZE){
×
4224
                        if(PF_RawSend(to,buf,PF_SNDFILEBUFSIZE,PF_BUFFER_MSGTAG))
×
4225
                                return(-1);
×
4226
                }
4227
                else{
4228
                        if(PF_RawSend(to,buf,l,PF_ENDBUFFER_MSGTAG))
×
4229
                                return(-1);
4230
                        break;
×
4231
                }
4232
        }/*for(;;)*/
4233
        return(len);
×
4234
}
4235

4236
/*
4237
          #] PF_SendFile : 
4238
          #[ PF_RecvFile :
4239
*/
4240

4241
/**
4242
 * Receives a file from the process specified by \a from.
4243
 *
4244
 * @param  from  the source process number.
4245
 * @param  fd    the file to save the received data.
4246
 * @return       the size of received data in bytes, or -1 on error.
4247
 */
4248
int PF_RecvFile(int from, FILE *fd)
×
4249
{
4250
        size_t len=0;
×
4251
        int tag;
×
4252
        do{
×
4253
                char buf[PF_SNDFILEBUFSIZE];
×
4254
                int l;
×
4255
                        l=PF_RawRecv(&from,buf,PF_SNDFILEBUFSIZE,&tag);
×
4256
                        if(l<0)
×
4257
                                return(-1);
×
4258
                        if(tag == PF_EMPTY_MSGTAG)
×
4259
                                return(-1);
4260

4261
                        if( fwrite(buf,l,1,fd)!=1 )
×
4262
                                return(-1);
4263
                        len+=l;
×
4264
        }while(tag!=PF_ENDBUFFER_MSGTAG);
×
4265
        return(len);
×
4266
}
4267

4268
/*
4269
          #] PF_RecvFile : 
4270
          #[ Synchronised output :
4271
                 #[ Explanations :
4272
*/
4273

4274
/*
4275
 * If the master and slaves output statistics or error messages to the same stream
4276
 * or file (e.g., the standard output or the log file) simultaneously, then
4277
 * a mixing of their outputs can occur. To avoid this, TFORM uses a lock of
4278
 * ErrorMessageLock, but there is no locking functionality in the original MPI
4279
 * specification. We need to synchronise the output from the master and slaves.
4280
 *
4281
 * The idea of the synchronised output (by, e.g., MesPrint()) implemented here is
4282
 *   Slaves:
4283
 *     1. Save the output by WriteFile() (set to PF_WriteFileToFile())
4284
 *        into some buffers between MLOCK(ErrorMessageLock) and
4285
 *        MUNLOCK(ErrorMessageLock), which call PF_MLock() and PF_MUnlock(),
4286
 *        respectively. The output for AM.StdOut and AC.LogHandle are saved to
4287
 *        the buffers.
4288
 *     2. At MUNLOCK(ErrorMessageLock), send the output in the buffer to the master,
4289
 *        with PF_STDOUT_MSGTAG or PF_LOG_MSGTAG.
4290
 *   Master:
4291
 *     1. Receive the buffered output from slaves, and write them by
4292
 *        WriteFileToFile().
4293
 *   The main problem is how and where the master receives messages from
4294
 *   the slaves (PF_ReceiveErrorMessage()). For this purpose there are three
4295
 *   helper functions: PF_CatchErrorMessages() and PF_CatchErrorMessagesForAll()
4296
 *   which remove messages with PF_STDOUT_MSGTAG or PF_LOG_MSGTAG from the top
4297
 *   of the message queue, and PF_ProbeWithCatchingErrorMessages() which is same as
4298
 *   PF_Probe() except removing these messages.
4299
 */
4300

4301
/*
4302
                 #] Explanations : 
4303
                 #[ Variables :
4304
*/
4305

4306
static int errorMessageLock = 0;     /* (slaves) The lock count. See PF_MLock() and PF_MUnlock(). */
4307
static Vector(UBYTE, stdoutBuffer);  /* (slaves) The buffer for AM.StdOut. */
4308
static Vector(UBYTE, logBuffer);     /* (slaves) The buffer for AC.LogHandle. */
4309
#define recvBuffer logBuffer         /* (master) The buffer for receiving messages. */
4310

4311
/*
4312
 * If PF_ENABLE_STDOUT_BUFFERING is defined, the master performs the line buffering
4313
 * (using stdoutBuffer) at PF_WriteFileToFile().
4314
 */
4315
#ifndef PF_ENABLE_STDOUT_BUFFERING
4316
#ifdef UNIX
4317
#define PF_ENABLE_STDOUT_BUFFERING
4318
#endif
4319
#endif
4320

4321
/*
4322
                 #] Variables : 
4323
                 #[ PF_MLock :
4324
*/
4325

4326
/**
4327
 * A function called by MLOCK(ErrorMessageLock) for slaves.
4328
 */
4329
void PF_MLock(void)
258✔
4330
{
4331
        /* Only on slaves. */
4332
        if ( errorMessageLock++ > 0 ) return;
258✔
4333
        VectorClear(stdoutBuffer);
258✔
4334
        VectorClear(logBuffer);
258✔
4335
}
4336

4337
/*
4338
                 #] PF_MLock : 
4339
                 #[ PF_MUnlock :
4340
*/
4341

4342
/**
4343
 * A function called by MUNLOCK(ErrorMessageLock) for slaves.
4344
 */
4345
void PF_MUnlock(void)
258✔
4346
{
4347
        /* Only on slaves. */
4348
        if ( --errorMessageLock > 0 ) return;
258✔
4349
        if ( !VectorEmpty(stdoutBuffer) ) {
258✔
4350
                PF_RawSend(MASTER, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer), PF_STDOUT_MSGTAG);
231✔
4351
        }
4352
        if ( !VectorEmpty(logBuffer) ) {
258✔
4353
                PF_RawSend(MASTER, VectorPtr(logBuffer), VectorSize(logBuffer), PF_LOG_MSGTAG);
×
4354
        }
4355
}
4356

4357
/*
4358
                 #] PF_MUnlock : 
4359
                 #[ PF_WriteFileToFile :
4360
*/
4361

4362
/**
4363
 * Replaces WriteFileToFile() on the master and slaves.
4364
 *
4365
 * It copies the given buffer into internal buffers if called between
4366
 * MLOCK(ErrorMessageLock) and MUNLOCK(ErrorMessageLock) for slaves and
4367
 * handle is StdOut or LogHandle, otherwise calls WriteFileToFile().
4368
 *
4369
 * @param  handle  a file handle that specifies the output.
4370
 * @param  buffer  a pointer to the source buffer containing the data to be written.
4371
 * @param  size    the size of data to be written in bytes.
4372
 * @return         the actual size of data written to the output in bytes.
4373
 */
4374
LONG PF_WriteFileToFile(int handle, UBYTE *buffer, LONG size)
15,061✔
4375
{
4376
        if ( PF.me != MASTER && errorMessageLock > 0 ) {
15,061✔
4377
                if ( handle == AM.StdOut ) {
237✔
4378
                        VectorPushBacks(stdoutBuffer, buffer, size);
237✔
4379
                        return size;
237✔
4380
                }
4381
                else if ( handle == AC.LogHandle ) {
×
4382
                        VectorPushBacks(logBuffer, buffer, size);
×
4383
                        return size;
×
4384
                }
4385
        }
4386
#ifdef PF_ENABLE_STDOUT_BUFFERING
4387
        /*
4388
         * On my computer, sometimes a single linefeed "\n" sent to the standard
4389
         * output is ignored on the execution of mpiexec. A typical example is:
4390
         *   $ cat foo.c
4391
         *     #include <unistd.h>
4392
         *     int main() {
4393
         *       write(1, "    ", 4);
4394
         *       write(1, "\n", 1);
4395
         *       write(1, "    ", 4);
4396
         *       write(1, "123\n", 4);
4397
         *       return 0;
4398
         *     }
4399
         * or even as a shell script:
4400
         *   $ cat foo.sh
4401
         *     #! bin/sh
4402
         *     printf "    "
4403
         *     printf "\n"
4404
         *     printf "    "
4405
         *     printf "123\n"
4406
         * When I ran it on mpiexec
4407
         *   $ while :; do mpiexec -np 1 ./foo.sh; done
4408
         * I observed the single linefeed (printf "\n") was sometimes ignored. Even
4409
         * though this phenomenon might be specific to my environment, I added this
4410
         * code because someone may encounter a similar phenomenon and feel it
4411
         * frustrating. (TU 16 Jun 2011)
4412
         *
4413
         * Phenomenon:
4414
         *   A single linefeed sent to the standard output occasionally ignored
4415
         *   on mpiexec.
4416
         *
4417
         * Environment:
4418
         *   openSUSE 11.4 (x86_64)
4419
         *   kernel: 2.6.37.6-0.5-desktop
4420
         *   gcc: 4.5.1 20101208
4421
         *   mpich2-1.3.2p1 configured with '--enable-shared --with-pm=smpd'
4422
         *
4423
         * Solution:
4424
         *   In Unix (in which Uwrite() calls write() system call without any buffering),
4425
         *   we perform the line buffering here. A single linefeed is also buffered.
4426
         *
4427
         * XXX:
4428
         *   At the end of the program the buffered output (text without LF) will not be flushed,
4429
         *   i.e., will not be written to the standard output. This is not problematic at a normal run.
4430
         *   The buffer can be explicitly flushed by PF_FlushStdOutBuffer().
4431
         */
4432
        if ( PF.me == MASTER && handle == AM.StdOut ) {
14,824✔
4433
                size_t oldsize;
14,069✔
4434
                /* Assume the newline character is LF (when UNIX is defined). */
4435
                if ( (size > 0 && buffer[size - 1] != LINEFEED) || (size == 1 && buffer[0] == LINEFEED) ) {
14,069✔
4436
                        VectorPushBacks(stdoutBuffer, buffer, size);
5,157✔
4437
                        return size;
5,157✔
4438
                }
4439
                if ( (oldsize = VectorSize(stdoutBuffer)) > 0 ) {
8,912✔
4440
                        LONG ret;
4,684✔
4441
                        VectorPushBacks(stdoutBuffer, buffer, size);
4,684✔
4442
                        ret = WriteFileToFile(handle, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer));
4,684✔
4443
                        VectorClear(stdoutBuffer);
4,684✔
4444
                        if ( ret < 0 ) {
4,684✔
4445
                                return ret;
4446
                        }
4447
                        else if ( ret < (LONG)oldsize ) {
4,684✔
4448
                                return 0;  /* This means the buffered output in previous calls is lost. */
4449
                        }
4450
                        else {
4451
                                return ret - (LONG)oldsize;
4,684✔
4452
                        }
4453
                }
4454
        }
4455
#endif
4456
        return WriteFileToFile(handle, buffer, size);
4,983✔
4457
}
4458

4459
/*
4460
                 #] PF_WriteFileToFile : 
4461
                 #[ PF_FlushStdOutBuffer :
4462
*/
4463

4464
/**
4465
 * Explicitly Flushes the buffer for the standard output on the master, which is
4466
 * used if PF_ENABLE_STDOUT_BUFFERING is defined.
4467
 */
4468
void PF_FlushStdOutBuffer(void)
×
4469
{
4470
#ifdef PF_ENABLE_STDOUT_BUFFERING
4471
        if ( PF.me == MASTER && VectorSize(stdoutBuffer) > 0 ) {
×
4472
                WriteFileToFile(AM.StdOut, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer));
×
4473
                VectorClear(stdoutBuffer);
×
4474
        }
4475
#endif
4476
}
×
4477

4478
/*
4479
                 #] PF_FlushStdOutBuffer : 
4480
                 #[ PF_ReceiveErrorMessage :
4481
*/
4482

4483
/**
4484
 * Receives an error message from a slave's PF_MUnlock() call, and writes
4485
 * the message to the corresponding output.
4486
 * instead of LOCK(ErrorMessageLock) and UNLOCK(ErrorMessageLock).
4487
 *
4488
 * @param  src  the source process.
4489
 * @param  tag  the tag value (must be PF_STDOUT_MSGTAG or PF_LOG_MSGTAG or PF_ANY_MSGTAG).
4490
 */
4491
static void PF_ReceiveErrorMessage(int src, int tag)
231✔
4492
{
4493
        /* Only on the master. */
4494
        int size;
231✔
4495
        int ret = PF_RawProbe(&src, &tag, &size);
231✔
4496
        CHECK(ret == 0);
231✔
4497
        switch ( tag ) {
231✔
4498
                case PF_STDOUT_MSGTAG:
231✔
4499
                case PF_LOG_MSGTAG:
4500
                        VectorReserve(recvBuffer, size);
231✔
4501
                        ret = PF_RawRecv(&src, VectorPtr(recvBuffer), size, &tag);
231✔
4502
                        CHECK(ret == size);
231✔
4503
                        if ( size > 0 ) {
231✔
4504
                                int handle = (tag == PF_STDOUT_MSGTAG) ? AM.StdOut : AC.LogHandle;
231✔
4505
#ifdef PF_ENABLE_STDOUT_BUFFERING
4506
                                if ( handle == AM.StdOut ) PF_WriteFileToFile(handle, VectorPtr(recvBuffer), size);
231✔
4507
                                else
4508
#endif
4509
                                WriteFileToFile(handle, VectorPtr(recvBuffer), size);
×
4510
                        }
4511
                        break;
4512
        }
4513
}
231✔
4514

4515
/*
4516
                 #] PF_ReceiveErrorMessage : 
4517
                 #[ PF_CatchErrorMessages :
4518
*/
4519

4520
/**
4521
 * Processes all incoming messages whose tag is PF_STDOUT_MSGTAG
4522
 * or PF_LOG_MSGTAG. It ensures that the next PF_Receive(src, tag, ...)
4523
 * will not receive the message with PF_STDOUT_MSGTAG or PF_LOG_MSGTAG.
4524
 *
4525
 * @param[in,out]  src  the source process.
4526
 * @param[in,out]  tag  the tag value.
4527
 */
4528
static void PF_CatchErrorMessages(int *src, int *tag)
14,083✔
4529
{
4530
        /* Only on the master. */
4531
        for (;;) {
14,154✔
4532
                int asrc = *src;
14,154✔
4533
                int atag = *tag;
14,154✔
4534
                int ret = PF_RawProbe(&asrc, &atag, NULL);
14,154✔
4535
                CHECK(ret == 0);
14,154✔
4536
                if ( atag == PF_STDOUT_MSGTAG || atag == PF_LOG_MSGTAG ) {
14,154✔
4537
                        PF_ReceiveErrorMessage(asrc, atag);
71✔
4538
                        continue;
71✔
4539
                }
4540
                *src = asrc;
14,083✔
4541
                *tag = atag;
14,083✔
4542
                break;
14,083✔
4543
        }
4544
}
14,083✔
4545

4546
/*
4547
                 #] PF_CatchErrorMessages : 
4548
                 #[ PF_CatchErrorMessagesForAll :
4549
*/
4550

4551
/**
4552
 * Calls PF_CatchErrorMessages() for all slaves and PF_ANY_MSGTAG.
4553
 * Note that it is NOT equivalent to PF_CatchErrorMessages() with PF_ANY_SOURCE.
4554
 */
4555
static void PF_CatchErrorMessagesForAll(void)
2,057✔
4556
{
4557
        /* Only on the master. */
4558
        int i;
2,057✔
4559
        for ( i = 1; i < PF.numtasks; i++ ) {
8,228✔
4560
                int src = i;
6,171✔
4561
                int tag = PF_ANY_MSGTAG;
6,171✔
4562
                PF_CatchErrorMessages(&src, &tag);
6,171✔
4563
        }
4564
}
2,057✔
4565

4566
/*
4567
                 #] PF_CatchErrorMessagesForAll : 
4568
                 #[ PF_ProbeWithCatchingErrorMessages :
4569
*/
4570

4571
/**
4572
 * Same as PF_Probe() except processing incoming messages with PF_STDOUT_MSGTAG
4573
 * and PF_LOG_MSGTAG.
4574
 *
4575
 * @param[in,out]  src  the source process. The output value is that of the actual found message.
4576
 * @return              the tag value of the next incoming message if found,
4577
 *                      0 if a nonblocking probe (input src != PF_ANY_SOURCE) did not
4578
 *                      find any messages. The negative returned value indicates an error.
4579
 */
4580
static int PF_ProbeWithCatchingErrorMessages(int *src)
14,906,500✔
4581
{
4582
        for (;;) {
14,906,700✔
4583
                int newsrc = *src;
14,906,700✔
4584
                int tag = PF_Probe(&newsrc);
14,906,700✔
4585
                if ( tag == PF_STDOUT_MSGTAG || tag == PF_LOG_MSGTAG ) {
14,906,700✔
4586
                        PF_ReceiveErrorMessage(newsrc, tag);
160✔
4587
                        continue;
160✔
4588
                }
4589
                if ( tag > 0 ) *src = newsrc;
14,906,500✔
4590
                return tag;
14,906,500✔
4591
        }
4592
}
4593

4594
/*
4595
                 #] PF_ProbeWithCatchingErrorMessages : 
4596
                 #[ PF_FreeErrorMessageBuffers :
4597
*/
4598

4599
/**
4600
 * Frees the buffers allocated for the synchronized output.
4601
 *
4602
 * Currently, not used anywhere, but could be used in PF_Terminate().
4603
 */
4604
void PF_FreeErrorMessageBuffers(void)
×
4605
{
4606
        VectorFree(stdoutBuffer);
×
4607
        VectorFree(logBuffer);
×
4608
}
×
4609

4610
/*
4611
                 #] PF_FreeErrorMessageBuffers : 
4612
          #] Synchronised output : 
4613
*/
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc