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

tueda / form / 12516247166

27 Dec 2024 12:47PM UTC coverage: 50.678% (-0.05%) from 50.724%
12516247166

push

github

tueda
debug

42035 of 82946 relevant lines covered (50.68%)

1401654.15 hits per line

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

87.06
/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)
10,544✔
196
{
197
        GETIDENTITY
198
        LONG real, cpu;
10,544✔
199
        WORD rpart, cpart;
10,544✔
200
        int i, j;
10,544✔
201

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

205
                if ( PF_stats == NULL ) {
10,539✔
206
                        PF_stats = (LONG**)Malloc1(PF.numtasks*sizeof(LONG*),"PF_stats 1");
231✔
207
                        for ( i = 0; i < PF.numtasks; i++ ) {
1,155✔
208
                                PF_stats[i] = (LONG*)Malloc1(PF_STATS_SIZE*sizeof(LONG),"PF_stats 2");
924✔
209
                                for ( j = 0; j < PF_STATS_SIZE; j++ ) PF_stats[i][j] = 0;
5,544✔
210
                        }
211
                }
212
                if ( proc > 0 ) for ( i = 0; i < PF_STATS_SIZE; i++ ) PF_stats[proc][i] = stats[0][i];
61,221✔
213

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

217
                        for ( i = 0; i < PF_STATS_SIZE; i++ ) sum[i] = 0;
12,552✔
218
                        sum[0] = cpu = TimeCPU(1);
2,092✔
219
                        cpart = (WORD)(cpu%1000);
2,092✔
220
                        cpu /= 1000;
2,092✔
221
                        cpart /= 10;
2,092✔
222
                        if ( AC.OldParallelStats ) MesPrint("");
2,092✔
223
                        if ( proc > 0 && AC.StatsFlag && AC.OldParallelStats ) {
2,092✔
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,092✔
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,368✔
233
                                cpart = (WORD)(PF_stats[i][0]%1000);
6,276✔
234
                                cpu = PF_stats[i][0] / 1000;
6,276✔
235
                                cpart /= 10;
6,276✔
236
                                if ( AC.StatsFlag && AC.OldParallelStats )
6,276✔
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,656✔
240
                        }
241
                        cpart = (WORD)(sum[0]%1000);
2,092✔
242
                        cpu = sum[0] / 1000;
2,092✔
243
                        cpart /= 10;
2,092✔
244
                        if ( AC.StatsFlag && AC.OldParallelStats ) {
2,092✔
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,092✔
251
                }
252
        }
253
        return(0);
10,544✔
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,848✔
312
{
313
        PF_BUFFER *buf;
1,848✔
314
        UBYTE *p, *stop;
1,848✔
315
        LONG allocsize;
1,848✔
316
        int i;
1,848✔
317

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

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

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

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

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

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

346
        for ( i = 0; i < buf->numbufs; i++ ) buf->request[i] = MPI_REQUEST_NULL;
5,775✔
347
        buf->tag     = (int *)p;                  p += buf->numbufs*sizeof(int);
1,848✔
348
        buf->from    = (int *)p;                  p += buf->numbufs*sizeof(int);
1,848✔
349
/*
350
                and finally the real bufferspace
351
*/
352
        for ( i = free; i < buf->numbufs; i++ ) {
3,234✔
353
                buf->buff[i] = (WORD*)p; p += bsize;
1,386✔
354
                buf->stop[i] = (WORD*)p;
1,386✔
355
                buf->fill[i] = buf->full[i] = buf->buff[i];
1,386✔
356
        }
357
        if ( p != stop ) {
1,848✔
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,092✔
381
{
382
        GETIDENTITY
383
        PF_BUFFER **rbuf = PF.rbufs;
2,092✔
384
        UBYTE *p, *stop;
2,092✔
385
        int numrbufs,numtasks = PF.numtasks;
2,092✔
386
        int i, j, src, numnodes;
2,092✔
387
        int numslaves = numtasks - 1;
2,092✔
388
        LONG size;
2,092✔
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,092✔
394
                size =  2*numtasks*sizeof(WORD*) + sizeof(WORD)*
231✔
395
                        ( numtasks*(1 + AM.MaxTal) + (AM.MaxTer/sizeof(WORD)+1) + 2*(AM.MaxTal+2));
231✔
396

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

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

410
                if ( p != stop ) { MesPrint("error in PF_InitTree"); return(-1); }
231✔
411
        }
412
/*
413
                 #] the buffers : 
414
                 #[ the receive buffers :
415
*/
416
        numrbufs = PF.numrbufs;
2,092✔
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,092✔
421

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

439
        for ( i = 1; i < numtasks; i++ ) {
8,368✔
440
                for ( j = 0; j < rbuf[i]->numbufs; j++ ) {
18,828✔
441
                        rbuf[i]->full[j] = rbuf[i]->fill[j] = rbuf[i]->buff[j] + AM.MaxTer/sizeof(WORD) + 2;
12,552✔
442
                }
443
                PF_term[i] = rbuf[i]->fill[rbuf[i]->active];
6,276✔
444
                *PF_term[i] = 0;
6,276✔
445
                PF_IRecvRbuf(rbuf[i],rbuf[i]->active,i);
6,276✔
446
        }
447
        rbuf[0]->active = 0;
2,092✔
448
        PF_term[0] = rbuf[0]->buff[0];
2,092✔
449
        PF_term[0][0] = 0;  /* PF_term[0] is used for a zero term. */
2,092✔
450
        PF.rbufs = rbuf;
2,092✔
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,092✔
458
        else {
459
                numnodes = 2;
460
                while ( numnodes < numslaves ) numnodes *= 2;
4,184✔
461
                numnodes -= 1;
2,092✔
462
        }
463

464
        if ( PF_root == NULL )
2,092✔
465
        if ( ( PF_root = (NODE*)Malloc1(sizeof(NODE)*numnodes,"nodes in mergetree") ) == NULL )
231✔
466
                return(-1);
467
/*
468
                then initialize all the nodes
469
*/
470
        src = 1;
471
        for ( i = 0; i < numnodes; i++ ) {
8,368✔
472
                if ( 2*(i+1) <= numnodes ) {
6,276✔
473
                        PF_root[i].left = &(PF_root[2*(i+1)-1]);
2,092✔
474
                        PF_root[i].lsrc = 0;
2,092✔
475
                }
476
                else {
477
                        PF_root[i].left = 0;
4,184✔
478
                        if ( src < numtasks ) PF_root[i].lsrc = src++;
4,184✔
479
                        else                  PF_root[i].lsrc = 0;
×
480
                }
481
                PF_root[i].lloser = 0;
6,276✔
482
        }
483
        for ( i = 0; i < numnodes; i++ ) {
8,368✔
484
                if ( 2*(i+1)+1 <= numnodes ) {
6,276✔
485
                        PF_root[i].rght = &(PF_root[2*(i+1)]);
2,092✔
486
                        PF_root[i].rsrc = 0;
2,092✔
487
                }
488
                else {
489
                        PF_root[i].rght = 0;
4,184✔
490
                        if (src<numtasks) PF_root[i].rsrc = src++;
4,184✔
491
                        else              PF_root[i].rsrc = 0;
2,092✔
492
                }
493
                PF_root[i].rloser = 0;
6,276✔
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,456,640✔
525
{
526
        int tag;
2,456,640✔
527
        WORD im, r;
2,456,640✔
528
        WORD *m1, *m2;
2,456,640✔
529
        LONG size;
2,456,640✔
530
        PF_BUFFER *rbuf = PF.rbufs[src];
2,456,640✔
531
        int a = rbuf->active;
2,456,640✔
532
        int next = a+1 >= rbuf->numbufs ? 0 : a+1 ;
2,456,640✔
533
        WORD *lastterm = PF_term[src];
2,456,640✔
534
        WORD *term = rbuf->fill[a];
2,456,640✔
535

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

538
        if ( rbuf->full[a] == rbuf->buff[a] + AM.MaxTer/sizeof(WORD) + 2 ) {
2,454,550✔
539
/*
540
                        very first term from this src
541
*/
542
                tag = PF_WaitRbuf(rbuf,a,&size);
6,276✔
543
                rbuf->full[a] += size;
6,276✔
544
                if ( tag == PF_ENDBUFFER_MSGTAG ) *rbuf->full[a]++ = 0;
6,276✔
545
                else if ( rbuf->numbufs > 1 ) {
2✔
546
/*
547
                                post a nonblock. recv. for the next buffer
548
*/
549
                        rbuf->full[next] = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 2;
2✔
550
                        size = (LONG)(rbuf->stop[next] - rbuf->full[next]);
2✔
551
                        PF_IRecvRbuf(rbuf,next,src);
2✔
552
                }
553
        }
554
        if ( *term == 0 && term != rbuf->full[a] ) return(PF_term[0]);
2,454,550✔
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,448,280✔
559
newterms:
9✔
560
                m1 = rbuf->buff[next] + AM.MaxTer/sizeof(WORD) + 1;
10✔
561
                if ( *term < 0 || term == rbuf->full[a] ) {
10✔
562
/*
563
                        copy term and lastterm to the new buffer, so that they end at m1
564
*/
565
                        m2 = rbuf->full[a] - 1;
2✔
566
                        while ( m2 >= term ) *m1-- = *m2--;
3✔
567
                        rbuf->fill[next] = term = m1 + 1;
2✔
568
                        m2 = lastterm + *lastterm - 1;
2✔
569
                        while ( m2 >= lastterm ) *m1-- = *m2--;
44✔
570
                        lastterm = m1 + 1;
2✔
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;
8✔
577
                        while ( m2 >= term ) *m1-- = *m2--;
128✔
578
                        rbuf->fill[next] = term = m1 + 1;
8✔
579
                }
580
                if ( rbuf->numbufs == 1 ) {
10✔
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;
10✔
589
                tag = PF_WaitRbuf(rbuf,next,&size);
10✔
590
                rbuf->full[next] += size;
10✔
591
                if ( tag == PF_ENDBUFFER_MSGTAG ) {
10✔
592
                        *rbuf->full[next]++ = 0;
2✔
593
                }
594
                else if ( rbuf->numbufs > 1 ) {
8✔
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;
8✔
599
                        size = (LONG)(rbuf->stop[a] - rbuf->full[a]);
8✔
600
                        PF_IRecvRbuf(rbuf,a,src);
8✔
601
                }
602
/*
603
                        now safely make next buffer active
604
*/
605
                a = rbuf->active = next;
10✔
606
        }
607

608
        if ( *term < 0 ) {
2,448,280✔
609
/*
610
                        We need to decompress the term
611
*/
612
                im = *term;
407,370✔
613
                r = term[1] - im + 1;
407,370✔
614
                m1 = term + 2;
407,370✔
615
                m2 = lastterm - im + 1;
407,370✔
616
                while ( ++im <= 0 ) *--m1 = *--m2;
2,724,200✔
617
                *--m1 = r;
407,370✔
618
                rbuf->fill[a] = term = m1;
407,370✔
619
                if ( term + *term > rbuf->full[a] ) goto newterms;
407,370✔
620
        }
621
        rbuf->fill[a] += *term;
2,448,280✔
622
        return(term);
2,448,280✔
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,897,800✔
649
{
650
        GETIDENTITY
651
        WORD comp;
4,897,800✔
652

653
        if ( PF_loser == 0 ) {
4,897,800✔
654
/*
655
                        this is for the right initialization of the tree only
656
*/
657
                if ( n->left ) n->lloser = PF_GetLoser(n->left);
6,276✔
658
                else {
659
                        n->lloser = n->lsrc;
4,184✔
660
                        if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0) n->lloser = 0;
4,184✔
661
                }
662
                PF_loser = 0;
6,276✔
663
                if ( n->rght ) n->rloser = PF_GetLoser(n->rght);
6,276✔
664
                else{
665
                        n->rloser = n->rsrc;
4,184✔
666
                        if ( *(PF_term[n->rsrc] = PF_PutIn(n->rsrc)) == 0 ) n->rloser = 0;
4,184✔
667
                }
668
                PF_loser = 0;
6,276✔
669
        }
670
        else if ( PF_loser == n->lloser ) {
4,891,520✔
671
                if ( n->left ) n->lloser = PF_GetLoser(n->left);
4,878,690✔
672
                else {
673
                        n->lloser = n->lsrc;
2,442,700✔
674
                        if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0 ) n->lloser = 0;
2,442,700✔
675
                }
676
        }
677
        else if ( PF_loser == n->rloser ) {
12,834✔
678
newright:
12,834✔
679
                if ( n->rght ) n->rloser = PF_GetLoser(n->rght);
15,501✔
680
                else {
681
                        n->rloser = n->rsrc;
5,546✔
682
                        if ( *(PF_term[n->rsrc] = PF_PutIn(n->rsrc)) == 0 ) n->rloser = 0;
5,546✔
683
                }
684
        }
685
        if ( n->lloser > 0 && n->rloser > 0 ) {
4,900,470✔
686
                comp = CompareTerms(BHEAD PF_term[n->lloser],PF_term[n->rloser],(WORD)0);
17,009✔
687
                if ( comp > 0 )     return(n->lloser);
17,009✔
688
                else if (comp < 0 ) return(n->rloser);
7,554✔
689
                else {
690
/*
691
                 #[ terms are equal :
692
*/
693
                        WORD *lcpos, *rcpos;
2,667✔
694
                        UWORD *newcpos;
2,667✔
695
                        WORD lclen, rclen, newclen, newnlen;
2,667✔
696
                        SORTING *S = AT.SS;
2,667✔
697

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

707
                                if ( ( r1 = (int)*PF_term[n->lloser] ) <= 0 ) r1 = 20;
1,046✔
708
                                if ( ( r2 = (int)*PF_term[n->rloser] ) <= 0 ) r2 = 20;
1,046✔
709
                                tt1 = ml;
1,046✔
710
                                ml += S->PolyWise;
1,046✔
711
                                mr += S->PolyWise;
1,046✔
712
                                if ( S->PolyFlag == 2 ) {
1,046✔
713
                                        w = poly_ratfun_add(BHEAD ml,mr);
1,044✔
714
                                        if ( *tt1 + w[1] - ml[1] > AM.MaxTer/((LONG)sizeof(WORD)) ) {
1,044✔
715
                                                MesPrint("Term too complex in PolyRatFun addition. MaxTermSize of %10l is too small",AM.MaxTer);
×
716
                                                Terminate(-1);
×
717
                                        }
718
                                        AT.WorkPointer = w;
1,044✔
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];
1,046✔
729
                                if ( r1 <= FUNHEAD || ( w[FUNHEAD] == -SNUMBER && w[FUNHEAD+1] == 0 ) ) {
1,046✔
730
                                        goto cancelled;
963✔
731
                                }
732
                                if ( r1 == ml[1] ) {
83✔
733
                                        NCOPY(ml,w,r1);
62✔
734
                                }
735
                                else if ( r1 < ml[1] ) {
81✔
736
                                        r2 = ml[1] - r1;
7✔
737
                                        mr = w + r1;
7✔
738
                                        ml += ml[1];
7✔
739
                                        while ( --r1 >= 0 ) *--ml = *--mr;
83,050✔
740
                                        mr = ml - r2;
7✔
741
                                        r1 = S->PolyWise;
7✔
742
                                        while ( --r1 >= 0 ) *--ml = *--mr;
69✔
743
                                        *ml -= r2;
7✔
744
                                        PF_term[n->lloser] = ml;
7✔
745
                                }
746
                                else {
747
                                        r2 = r1 - ml[1];
74✔
748
                                        if ( r2 > 2*AM.MaxTal )
74✔
749
                                                MesPrint("warning: new term in polyfun is large");
×
750
                                        mr = tt1 - r2;
74✔
751
                                        r1 = S->PolyWise;
74✔
752
                                        ml = tt1;
74✔
753
                                        *ml += r2;
74✔
754
                                        PF_term[n->lloser] = mr;
74✔
755
                                        NCOPY(mr,ml,r1);
619✔
756
                                        r1 = w[1];
74✔
757
                                        NCOPY(mr,w,r1);
717,914✔
758
                                }
759
                                PF_newclen[n->rloser] = 0;
83✔
760
                                PF_loser = n->rloser;
83✔
761
                                goto newright;
2,667✔
762
/*
763
                        #] Here we work with PolyFun : 
764
*/
765
                        }
766
                        if ( ( lclen = PF_newclen[n->lloser] ) != 0 ) lcpos = PF_newcpos[n->lloser];
1,621✔
767
                        else {
768
                                lcpos = PF_term[n->lloser];
1,550✔
769
                                lclen = *(lcpos += *lcpos - 1);
1,550✔
770
                                lcpos -= ABS(lclen) - 1;
1,550✔
771
                        }
772
                        if ( ( rclen = PF_newclen[n->rloser] ) != 0 ) rcpos = PF_newcpos[n->rloser];
1,621✔
773
                        else {
774
                                rcpos = PF_term[n->rloser];
1,621✔
775
                                rclen = *(rcpos += *rcpos - 1);
1,621✔
776
                                rcpos -= ABS(rclen) -1;
1,621✔
777
                        }
778
                        lclen = ( (lclen > 0) ? (lclen-1) : (lclen+1) ) >> 1;
1,621✔
779
                        rclen = ( (rclen > 0) ? (rclen-1) : (rclen+1) ) >> 1;
1,621✔
780
                        newcpos = PF_ScratchSpace;
1,621✔
781
                        if ( AddRat(BHEAD (UWORD *)lcpos,lclen,(UWORD *)rcpos,rclen,newcpos,&newnlen) ) return(-1);
1,621✔
782
                        if ( AN.ncmod != 0 ) {
1,621✔
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,621✔
794
/*
795
                                        terms cancel, get loser of left subtree and then of right subtree
796
*/
797
cancelled:
1,120✔
798
                                PF_loser = n->lloser;
2,083✔
799
                                PF_newclen[n->lloser] = 0;
2,083✔
800
                                if ( n->left ) n->lloser = PF_GetLoser(n->left);
2,083✔
801
                                else {
802
                                        n->lloser = n->lsrc;
30✔
803
                                        if ( *(PF_term[n->lsrc] = PF_PutIn(n->lsrc)) == 0 ) n->lloser = 0;
30✔
804
                                }
805
                                PF_loser = n->rloser;
2,083✔
806
                                PF_newclen[n->rloser] = 0;
2,083✔
807
                                goto newright;
2,083✔
808
                        }
809
                        else {
810
/*
811
                                        keep the left term and get the loser of right subtree
812
*/
813
                                newnlen *= 2;
501✔
814
                                newclen = ( newnlen > 0 ) ? ( newnlen + 1 ) : ( newnlen - 1 );
501✔
815
                                if ( newnlen < 0 ) newnlen = -newnlen;
501✔
816
                                PF_newclen[n->lloser] = newclen;
501✔
817
                                lcpos = PF_newcpos[n->lloser];
501✔
818
                                if ( newclen < 0 ) newclen = -newclen;
501✔
819
                                while ( newclen-- ) *lcpos++ = *newcpos++;
2,028✔
820
                                PF_loser = n->rloser;
501✔
821
                                PF_newclen[n->rloser] = 0;
501✔
822
                                goto newright;
501✔
823
                        }
824
/*
825
                 #] terms are equal : 
826
*/
827
                }
828
        }
829
        if (n->lloser > 0) return(n->lloser);
4,883,460✔
830
        if (n->rloser > 0) return(n->rloser);
14,223✔
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)
1,108,830✔
865
{
866
        GETIDENTITY
867
        FILEHANDLE *fout = AR.outfile;
1,108,830✔
868
        PF_BUFFER *sbuf=PF.sbuf;
1,108,830✔
869
        SORTING *S = AT.SS;
1,108,830✔
870
        WORD *outterm,*pp;
1,108,830✔
871
        LONG size, noutterms;
1,108,830✔
872
        POSITION position, oldposition;
1,108,830✔
873
        WORD i,cc;
1,108,830✔
874
        int oldgzipCompress;
1,108,830✔
875

876
        if ( AT.SS != AT.S0 || !PF.parallel ) return 0;
1,108,830✔
877

878
        if ( PF.me != MASTER ) {
8,368✔
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,276✔
887
                size -= (AM.MaxTer/sizeof(WORD) + 2);
6,276✔
888
                if ( fout->POsize < (LONG)(size*sizeof(WORD)) ) size = fout->POsize/sizeof(WORD);
6,276✔
889
                if ( sbuf == NULL ) {
6,276✔
890
                        if ( (sbuf = PF_AllocBuf(PF.numsbufs, size*sizeof(WORD), 1)) == NULL ) return -1;
693✔
891
                        sbuf->active = 0;
693✔
892
                        PF.sbuf = sbuf;
693✔
893
                }
894
                sbuf->buff[0] = fout->PObuffer;
6,276✔
895
                sbuf->stop[0] = fout->PObuffer+size;
6,276✔
896
                if ( sbuf->stop[0] > fout->POstop ) return -1;
6,276✔
897
                for ( i = 0; i < PF.numsbufs; i++ )
18,828✔
898
                        sbuf->fill[i] = sbuf->full[i] = sbuf->buff[i];
12,552✔
899

900
                fout->PObuffer = sbuf->buff[sbuf->active];
6,276✔
901
                fout->POstop = sbuf->stop[sbuf->active];
6,276✔
902
                fout->POsize = size*sizeof(WORD);
6,276✔
903
                fout->POfill = fout->POfull = fout->PObuffer;
6,276✔
904
/*
905
                 #] the slaves have to initialize their sendbuffer : 
906
*/
907
                return(0);
6,276✔
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,092✔
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,092✔
919
        if ( AR.PolyFun == 0 ) { S->PolyFlag = 0; }
2,092✔
920
        else if ( AR.PolyFunType == 1 ) { S->PolyFlag = 1; }
550✔
921
        else if ( AR.PolyFunType == 2 ) {
544✔
922
                if ( AR.PolyFunExp == 2
544✔
923
                  || AR.PolyFunExp == 3 ) S->PolyFlag = 1;
544✔
924
                else                      S->PolyFlag = 2;
525✔
925
        }
926
        *AR.CompressPointer = 0;
2,092✔
927
        SeekScratch(fout, &position);
2,092✔
928
        oldposition = position;
2,092✔
929
        oldgzipCompress = AR.gzipCompress;
2,092✔
930
        AR.gzipCompress = 0;
2,092✔
931

932
        noutterms = 0;
2,092✔
933

934
        while ( PF_loser >= 0 ) {
2,445,620✔
935
                if ( (PF_loser = PF_GetLoser(PF_root)) == 0 ) break;
2,445,620✔
936
                outterm = PF_term[PF_loser];
2,443,530✔
937
                noutterms++;
2,443,530✔
938

939
                if ( PF_newclen[PF_loser] != 0 ) {
2,443,530✔
940
/*
941
                        #[ this is only when new coeff was too long :
942
*/
943
                        outterm = PF_WorkSpace;
430✔
944
                        pp = PF_term[PF_loser];
430✔
945
                        cc = *pp;
430✔
946
                        while ( cc-- ) *outterm++ = *pp++;
5,823✔
947
                        outterm = (outterm[-1] > 0) ? outterm-outterm[-1] : outterm+outterm[-1];
430✔
948
                        if ( PF_newclen[PF_loser] > 0 ) cc =  (WORD)PF_newclen[PF_loser] - 1;
430✔
949
                        else                            cc = -(WORD)PF_newclen[PF_loser] - 1;
4✔
950
                        pp =  PF_newcpos[PF_loser];
430✔
951
                        while ( cc-- ) *outterm++ = *pp++;
1,298✔
952
                        *outterm++ = PF_newclen[PF_loser];
430✔
953
                        *PF_WorkSpace = outterm - PF_WorkSpace;
430✔
954
                        outterm = PF_WorkSpace;
430✔
955
                        *PF_newcpos[PF_loser] = 0;
430✔
956
                        PF_newclen[PF_loser] = 0;
430✔
957
/*
958
                        #] this is only when new coeff was too long : 
959
*/
960
                }
961
                PRINTFBUF("PF_EndSort to PutOut: ",outterm,*outterm);
2,443,530✔
962
                PutOut(BHEAD outterm,&position,fout,1);
2,443,530✔
963
        }
964
        if ( FlushOut(&position,fout,0) ) {
2,092✔
965
                AR.gzipCompress = oldgzipCompress;
×
966
                return(-1);
×
967
        }
968
        S->TermsLeft = PF_goutterms = noutterms;
2,092✔
969
        DIFPOS(PF_exprsize, position, oldposition);
2,092✔
970
        AR.gzipCompress = oldgzipCompress;
2,092✔
971
        return(1);
2,092✔
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)
347,421✔
1007
{
1008
        GETIDENTITY
1009
        FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
347,421✔
1010
        WORD i;
347,421✔
1011
        WORD *next, *np, *last, *lp = 0, *nextstop, *tp=term;
347,421✔
1012

1013
        /* Only on the slaves. */
1014

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

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

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

1040
                if ( PF.log ) {
8,447✔
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);
8,447✔
1046

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

1052
                size = fi->POstop - fi->PObuffer - 1;
8,447✔
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);
8,447✔
1070

1071
                fi->POfill = fi->PObuffer;
8,447✔
1072
                /* Get AN.ninterms which sits in the first 2 WORDs. */
1073
                {
1074
                        LONG ninterms;
8,447✔
1075
                        UNPACK_LONG(fi->POfill, ninterms);
8,447✔
1076
                        if ( fi->POfill < fi->POfull ) {
8,447✔
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));
2,171✔
1078
                                AN.ninterms = ninterms - 1;
2,171✔
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));
8,447✔
1081
                        }
1082
                }
1083
                fi->POfull = fi->PObuffer + size;
8,447✔
1084
                if ( tag == PF_ENDSORT_MSGTAG ) *fi->POfull++ = 0;
8,447✔
1085
/*
1086
                 #] receive new terms from master : 
1087
*/
1088
          }
1089
          if ( PF_CurrentBracket ) *PF_CurrentBracket = 0;
8,447✔
1090
        }
1091
        if ( *fi->POfill == 0 ) {
347,435✔
1092
                fi->POfill = fi->POfull = fi->PObuffer;
6,276✔
1093
                *term = 0;
6,276✔
1094
                goto RegRet;
6,276✔
1095
        }
1096
        if ( AR.DeferFlag ) {
341,159✔
1097
                if ( !PF_CurrentBracket ) {
132✔
1098
/*
1099
                 #[ alloc space :
1100
*/
1101
                        PF_CurrentBracket =
12✔
1102
                                        (WORD*)Malloc1(AM.MaxTer,"PF_CurrentBracket");
6✔
1103
                        *PF_CurrentBracket = 0;
6✔
1104
/*
1105
                 #] alloc space : 
1106
*/
1107
                }
1108
                while ( *PF_CurrentBracket ) {  /* "for each term in the buffer" */
2,104✔
1109
/*
1110
                 #[ test : bracket & skip if it's equal to the last in PF_CurrentBracket
1111
*/
1112
                        next = fi->POfill;
2,086✔
1113
                        nextstop = next + *next; nextstop -= ABS(nextstop[-1]);
2,086✔
1114
                        next++;
2,086✔
1115
                        last = PF_CurrentBracket+1;
2,086✔
1116
                        while ( next < nextstop ) {
4,072✔
1117
/*
1118
                                        scan the next term and PF_CurrentBracket
1119
*/
1120
                                if ( *last == HAAKJE && *next == HAAKJE ) {
4,072✔
1121
/*
1122
                                        the part outside brackets is equal => skip this term
1123
*/
1124
                                        PRINTFBUF("PF_GetTerm skips",fi->POfill,*fi->POfill);
1,986✔
1125
                                        break;
1,986✔
1126
                                }
1127
/*
1128
                                        check if the current subterms are equal
1129
*/
1130
                                np = next; next += next[1];
2,086✔
1131
                                lp = last; last += last[1];
2,086✔
1132
                                while ( np < next ) if ( *lp++ != *np++ ) goto strip;
44,782✔
1133
                        }
1134
/*
1135
                                go on to next term
1136
*/
1137
                        fi->POfill += *fi->POfill;
1,986✔
1138
                        AN.deferskipped++;
1,986✔
1139
/*
1140
                                the usual checks
1141
*/
1142
                        if ( fi->POfill >= fi->POfull || fi->POfull == fi->PObuffer )
1,986✔
1143
                                goto ReceiveNew;
14✔
1144
                        if ( *fi->POfill == 0 ) {
1,972✔
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:
18✔
1160
                next = fi->POfill;
118✔
1161
                nextstop = next + *next; nextstop -= ABS(nextstop[-1]);
118✔
1162
                next++;
118✔
1163
                tp++;
118✔
1164
                lp = PF_CurrentBracket + 1;
118✔
1165
                while ( next < nextstop ) {
235✔
1166
                        if ( *next == HAAKJE ) {
235✔
1167
                                fi->POfill += *fi->POfill;
118✔
1168
                                while ( next < fi->POfill ) *lp++ = *next++;
1,322✔
1169
                                *PF_CurrentBracket = lp - PF_CurrentBracket;
118✔
1170
                                *lp = 0;
118✔
1171
                                *tp++ = 1;
118✔
1172
                                *tp++ = 1;
118✔
1173
                                *tp++ = 3;
118✔
1174
                                *term = WORDDIF(tp,term);
118✔
1175
                                PRINTFBUF("PF_GetTerm new brack",PF_CurrentBracket,*PF_CurrentBracket);
118✔
1176
                                PRINTFBUF("PF_GetTerm POfill",fi->POfill,*fi->POfill);
118✔
1177
                                goto RegRet;
118✔
1178
                        }
1179
                        np = next; next += next[1];
117✔
1180
                        while ( np < next ) *tp++ = *lp++ = *np++;
2,545✔
1181
                }
1182
                tp = term;
1183
/*
1184
                 #] copy : 
1185
*/
1186
        }
1187

1188
        i = *fi->POfill;
341,027✔
1189
        while ( i-- ) *tp++ = *fi->POfill++;
8,743,920✔
1190
RegRet:
341,027✔
1191
        PRINTFBUF("PF_GetTerm returns",term,*term);
347,421✔
1192
        return(*term);
347,421✔
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,260✔
1209
{
1210
        GETIDENTITY
1211
        WORD *bra, *bstop;
2,027,260✔
1212
        WORD *tstart;
2,027,260✔
1213
        FILEHANDLE *fi = AC.RhsExprInModuleFlag && PF.rhsInParallel ? &PF.slavebuf : AR.infile;
2,027,260✔
1214
        WORD *next = fi->POfill;
2,027,260✔
1215
        WORD *termout = AT.WorkPointer;
2,027,260✔
1216
        WORD *oldwork = AT.WorkPointer;
2,027,260✔
1217

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

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

1224
        bra = bstop = PF_CurrentBracket;
2,027,260✔
1225
        if ( *bstop > 0 ) {
2,027,260✔
1226
                bstop += *bstop;
2,027,260✔
1227
                bstop -= ABS(bstop[-1]);
2,027,260✔
1228
        }
1229
        bra++;
2,027,260✔
1230
        while ( *bra != HAAKJE && bra < bstop ) bra += bra[1];
4,054,510✔
1231
        if ( bra >= bstop ) {        /* No deferred action! */
2,027,260✔
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,260✔
1239
        tstart = bra + bra[1];
2,027,260✔
1240
        bra = PF_CurrentBracket;
2,027,260✔
1241
        tstart--;
2,027,260✔
1242
        *tstart = bra + *bra - tstart;
2,027,260✔
1243
        bra++;
2,027,260✔
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,035,200✔
1251
                if ( InsertTerm(BHEAD term,0,AM.rbufnum,tstart,termout,0) < 0 ) {
2,031,230✔
1252
                        goto DefCall;
×
1253
                }
1254
/*
1255
                        call Generator with new composed term
1256
*/
1257
                AT.WorkPointer = termout + *termout;
2,031,230✔
1258
                if ( Generator(BHEAD termout,level) ) goto DefCall;
2,031,230✔
1259
                AT.WorkPointer = termout;
2,031,230✔
1260
                tstart = next + 1;
2,031,230✔
1261
                if ( tstart >= fi->POfull ) goto ThatsIt;
2,031,230✔
1262
                next += *next;
4,172✔
1263
/*
1264
                        compare with current bracket
1265
*/
1266
                while ( bra <= bstop ) {
93,536✔
1267
                        if ( *bra != *tstart ) goto ThatsIt;
89,564✔
1268
                        bra++; tstart++;
89,364✔
1269
                }
1270
/*
1271
                        now bra and tstart should both be a HAAKJE
1272
*/
1273
                bra--; tstart--;
3,972✔
1274
                if ( *bra != HAAKJE || *tstart != HAAKJE ) goto ThatsIt;
3,972✔
1275
                tstart += tstart[1];
3,972✔
1276
                tstart--;
3,972✔
1277
                *tstart = next - tstart;
3,972✔
1278
                bra = PF_CurrentBracket + 1;
3,972✔
1279
        }
1280

1281
ThatsIt:
2,027,260✔
1282
/*
1283
        AT.WorkPointer = oldwork;
1284
*/
1285
        AR.DeferFlag = 1;
2,027,260✔
1286
        return(0);
2,027,260✔
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)
8,447✔
1306
{
1307
        int j, tag, next;
8,447✔
1308

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

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

1324
        PF_Unpack(&j,1,PF_INT);
8,447✔
1325

1326
        if ( j ) {
8,447✔
1327
/*
1328
                actions depending on rest of information in last message
1329
*/
1330
        }
8,447✔
1331
        return(next);
8,447✔
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,093✔
1392
{
1393
        int i, readySlaves, tag, next = PF_ANY_SOURCE;
2,093✔
1394
        UBYTE *has_sent = 0;
2,093✔
1395

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

1399
        for ( readySlaves = 1; readySlaves < PF.numtasks; ) {
19,486,000✔
1400
                if ( next != PF_ANY_SOURCE) { /*Go to the next slave:*/
19,483,900✔
1401
                        do{ /*Note, here readySlaves<PF.numtasks, so this loop can't be infinite*/
54,341,900✔
1402
                                if ( ++next >= PF.numtasks ) next = 1;
54,341,900✔
1403
                        } while ( has_sent[next] == 1 );
54,341,900✔
1404
                }
1405
/*
1406
                        Here PF_ProbeWithCatchingErrorMessages() is BLOCKING function if next = PF_ANY_SOURCE:
1407
*/
1408
                tag = PF_ProbeWithCatchingErrorMessages(&next);
19,483,900✔
1409
/*
1410
                        Here next != PF_ANY_SOURCE
1411
*/
1412
                switch ( tag ) {
19,483,900✔
1413
                        case PF_BUFFER_MSGTAG:
6,276✔
1414
                        case PF_ENDBUFFER_MSGTAG:
1415
/*
1416
                                        Slaves are ready to send their results back
1417
*/
1418
                                if ( has_sent[next] == 0 ) {
6,276✔
1419
                                        has_sent[next] = 1;
6,276✔
1420
                                        readySlaves++;
6,276✔
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);
19,486,000✔
1474
                                }/*if ( has_sent[next] == 0 )*/
1475
                                break;
1476
                        case PF_READY_MSGTAG:
6,276✔
1477
/*
1478
                                        idle slave
1479
                                        May be only PF_READY_MSGTAG:
1480
*/
1481
                                next = PF_Wait4Slave(next);
6,276✔
1482
                                if ( next == -1 ) return(next); /*Cannot be!*/
6,276✔
1483
                                if ( has_sent[0] == 0 ) {  /*Send the last chunk to the slave*/
6,276✔
1484
                                        PF.sbuf->active = 0;
2,092✔
1485
                                        has_sent[0] = 1;
2,092✔
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,184✔
1493
/*
1494
                                                This will tell to the slave that there are no more terms:
1495
*/
1496
                                        *(PF.sbuf->fill[next])++ = 0;
4,184✔
1497
                                        PF.sbuf->active = next;
4,184✔
1498
                                }
1499
/*
1500
                                        Send ENDSORT
1501
*/
1502
                                PF_ISendSbuf(next,PF_ENDSORT_MSGTAG);
6,276✔
1503
                                break;
6,276✔
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,093✔
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,093✔
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,472✔
1541
{
1542
        GETIDENTITY
1543
        WORD *term = AT.WorkPointer;
8,472✔
1544
        LONG dd = 0;
8,472✔
1545
        PF_BUFFER *sb = PF.sbuf;
8,472✔
1546
        WORD j, *s, next;
8,472✔
1547
        LONG size, cpu;
8,472✔
1548
        POSITION position;
8,472✔
1549
        int k, src, tag;
8,472✔
1550
        FILEHANDLE *oldoutfile = AR.outfile;
8,472✔
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,472✔
1562

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

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

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

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

1586
                if ( PF.log && AC.CModule >= PF.log )
2,092✔
1587
                        MesPrint("[%d] working on expression %s in module %l",PF.me,EXPRNAME(i),AC.CModule);
×
1588
                if ( GetTerm(BHEAD term) <= 0 ) {
2,092✔
1589
                        MesPrint("[%d] Expression %d has problems in scratchfile",PF.me,i);
×
1590
                        return(-1);
×
1591
                }
1592
                term[3] = i;
2,092✔
1593
                if ( AR.outtohide ) {
2,092✔
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,091✔
1600
                        e->onfile = position;
2,091✔
1601
                        if ( PutOut(BHEAD term,&position,AR.outfile,0) < 0 ) return(-1);
2,091✔
1602
                }
1603
                AR.DeferFlag = 0;  /* The master leave the brackets!!! */
2,092✔
1604
                AR.Eside = RHSIDE;
2,092✔
1605
                if ( ( e->vflags & ISFACTORIZED ) != 0 ) {
2,092✔
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,092✔
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,092✔
1621
                if ( sb == 0 || sb->buff[0] != AT.SS->lBuffer ) {
2,092✔
1622
                        size = (LONG)((AT.SS->sTop2 - AT.SS->lBuffer)/(PF.numtasks));
551✔
1623
                        if ( size > (LONG)(AR.infile->POsize/sizeof(WORD) - 1) )
551✔
1624
                                size = AR.infile->POsize/sizeof(WORD) - 1;
2✔
1625
                        if ( sb == 0 ) {
551✔
1626
                                if ( ( sb = PF_AllocBuf(PF.numtasks,size*sizeof(WORD),PF.numtasks) ) == NULL )
231✔
1627
                                        return(-1);
1628
                        }
1629
                        sb->buff[0] = AT.SS->lBuffer;
551✔
1630
                        sb->full[0] = sb->fill[0] = sb->buff[0];
551✔
1631
                        for ( j = 1; j < PF.numtasks; j++ ) {
2,204✔
1632
                                sb->stop[j-1] = sb->buff[j] = sb->buff[j-1] + size;
1,653✔
1633
                        }
1634
                        sb->stop[PF.numtasks-1] = sb->buff[PF.numtasks-1] + size;
551✔
1635
                        PF.sbuf = sb;
551✔
1636
                }
1637
                for ( j = 0; j < PF.numtasks; j++ ) {
10,460✔
1638
                        sb->full[j] = sb->fill[j] = sb->buff[j];
8,368✔
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,092✔
1651
                if ( maxinterms > e->counter / (PF.numtasks - 1) / 4 )
2,092✔
1652
                        maxinterms = e->counter / (PF.numtasks - 1) / 4;
2,060✔
1653
                if ( maxinterms < 1 ) maxinterms = 1;
2,092✔
1654
                cmaxinterms = 0;
2,092✔
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,092✔
1662
                termsinbucket = 0;
2,092✔
1663
                PACK_LONG(sb->fill[0], 1);
2,092✔
1664
                while ( GetTerm(BHEAD term) ) {
345,223✔
1665
                        AN.ninterms++; dd = AN.deferskipped;
343,131✔
1666
                        if ( AC.CollectFun && *term <= (LONG)(AM.MaxTer/(2*sizeof(WORD))) ) {
343,131✔
1667
                                if ( GetMoreTerms(term) < 0 ) {
83✔
1668
                                        LowerSortLevel(); return(-1);
×
1669
                                }
1670
                        }
1671
                        PRINTFBUF("PF_Processor gets",term,*term);
343,131✔
1672
                        if ( termsinbucket >= maxinterms || sb->fill[0] + *term >= sb->stop[0] ) {
343,131✔
1673
                                next = PF_Wait4Slave(PF_ANY_SOURCE);
2,171✔
1674

1675
                                sb->fill[next] = sb->fill[0];
2,171✔
1676
                                sb->full[next] = sb->full[0];
2,171✔
1677
                                SWAP(sb->stop[next], sb->stop[0]);
2,171✔
1678
                                SWAP(sb->buff[next], sb->buff[0]);
2,171✔
1679
                                sb->fill[0] = sb->full[0] = sb->buff[0];
2,171✔
1680
                                sb->active = next;
2,171✔
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);
2,171✔
1688
#endif
1689
                                /* Initialize the next bucket. */
1690
                                termsinbucket = 0;
2,171✔
1691
                                PACK_LONG(sb->fill[0], AN.ninterms);
2,171✔
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 ) {
2,171✔
1697
                                        maxinterms *= 2;
850✔
1698
                                        if ( maxinterms >= ProcessBucketSize ) {
850✔
1699
                                                cmaxinterms = -1;
7✔
1700
                                                maxinterms = ProcessBucketSize;
7✔
1701
                                        }
1702
                                }
1703
                                else if ( cmaxinterms >= 0 ) {
1,321✔
1704
                                        cmaxinterms++;
913✔
1705
                                }
1706
                        }
1707
                        j = *(s = term);
343,131✔
1708
                        NCOPY(sb->fill[0], s, j);
8,817,100✔
1709
                        termsinbucket++;
343,131✔
1710
                }
1711
                /* NOTE: The last chunk will be sent to a slave at EndSort() => PF_EndSort()
1712
                 *       => PF_WaitAllSlaves(). */
1713
                AN.ninterms += dd;
2,092✔
1714
/*
1715
                        #] loop for all terms in infile: 
1716
                        #[ Clean up & EndSort:
1717
*/
1718
                if ( LastExpression ) {
2,092✔
1719
                        UpdateMaxSize();
437✔
1720
                        if ( AR.infile->handle >= 0 ) {
437✔
1721
                                CloseFile(AR.infile->handle);
1✔
1722
                                AR.infile->handle = -1;
1✔
1723
                                remove(AR.infile->name);
1✔
1724
                                PUTZERO(AR.infile->POposition);
1✔
1725
                        }
1726
                        AR.infile->POfill = AR.infile->POfull = AR.infile->PObuffer;
437✔
1727
                }
1728
                if ( AR.outtohide ) AR.outfile = AR.hidefile;
2,092✔
1729
                PF.parallel = 1;
2,092✔
1730
                if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) return(-1);
2,092✔
1731
                PF.parallel = 0;
2,092✔
1732
                if ( AR.outtohide ) {
2,092✔
1733
                        AR.outfile = oldoutfile;
1✔
1734
                        AR.hidefile->POfull = AR.hidefile->POfill;
1✔
1735
                }
1736
                UpdateMaxSize();
2,092✔
1737
                AR.BracketOn = oldBracketOn;
2,092✔
1738
                AT.BrackBuf = oldBrackBuf;
2,092✔
1739
                if ( ( e->vflags & TOBEFACTORED ) != 0 )
2,092✔
1740
                        poly_factorize_expression(e);
9✔
1741
                else if ( ( ( e->vflags & TOBEUNFACTORED ) != 0 )
2,083✔
1742
                 && ( ( e->vflags & ISFACTORIZED ) != 0 ) )
2,083✔
1743
                        poly_unfactorize_expression(e);
1✔
1744
                AT.bracketindexflag = oldbracketindexflag;
2,092✔
1745
                AR.GetFile = 0;
2,092✔
1746
                AR.outtohide = 0;
2,092✔
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,092✔
1756
                PF_CatchErrorMessagesForAll();
2,092✔
1757
                e->numdummies = 0;
2,092✔
1758
                for ( k = 1; k < PF.numtasks; k++ ) {
8,368✔
1759
                        PF_LongSingleReceive(PF_ANY_SOURCE, PF_ENDSORT_MSGTAG, &src, &tag);
6,276✔
1760
                        PF_LongSingleUnpack(PF_stats[src], PF_STATS_SIZE, PF_LONG);
6,276✔
1761
                        {
1762
                                WORD numdummies, expchanged;
6,276✔
1763
                                PF_LongSingleUnpack(&numdummies, 1, PF_WORD);
6,276✔
1764
                                PF_LongSingleUnpack(&expchanged, 1, PF_WORD);
6,276✔
1765
                                if ( e->numdummies < numdummies ) e->numdummies = numdummies;
6,276✔
1766
                                AR.expchanged |= expchanged;
6,276✔
1767
                        }
1768
                        /* Now handle redefined preprocessor variables. */
1769
                        if ( AC.numpfirstnum > 0 ) PF_UnpackRedefinedPreVars();
6,276✔
1770
                }
1771
                /* Broadcast redefined preprocessor variables. */
1772
                if ( AC.numpfirstnum > 0 ) {
2,092✔
1773
                        int RetCode = PF_BroadcastRedefinedPreVars();
7✔
1774
                        if ( RetCode ) return RetCode;
7✔
1775
                }
1776
                if ( ! AC.OldParallelStats ) {
2,092✔
1777
                        /* Now we can calculate AT.SS->GenTerms from the statistics of the slaves. */
1778
                        LONG genterms = 0;
1779
                        for ( k = 1; k < PF.numtasks; k++ ) {
8,368✔
1780
                                genterms += PF_stats[k][3];
6,276✔
1781
                        }
1782
                        AT.SS->GenTerms = genterms;
2,092✔
1783
                        WriteStats(&PF_exprsize, STATSPOSTSORT, NOCHECKLOGTYPE);
2,092✔
1784
                        Expressions[AR.CurExpr].size = PF_exprsize;
2,092✔
1785
                }
1786
                PF_Statistics(PF_stats,0);
2,092✔
1787
/*
1788
                        #] Collect (stats,prepro,...): 
1789
                        #[ Update flags :
1790
*/
1791
                if ( AM.S0->TermsLeft ) e->vflags &= ~ISZERO;
2,092✔
1792
                else e->vflags |= ISZERO;
466✔
1793
                if ( AR.expchanged == 0 ) e->vflags |= ISUNMODIFIED;
2,092✔
1794
                if ( AM.S0->TermsLeft ) AR.expflags |= ISZERO;
2,092✔
1795
                if ( AR.expchanged ) AR.expflags |= ISUNMODIFIED;
2,092✔
1796
/*
1797
                        #] Update flags : 
1798
                 #] Master: 
1799
*/
1800
        }
1801
        else {
1802
/*
1803
                 #[ Slave :
1804
*/
1805
/*
1806
                        #[ Generator Loop & EndSort :
1807

1808
                        loop for all terms to get from master, call Generator for each of them
1809
                        then call EndSort and do cleanup (to be implemented)
1810
*/
1811
                WORD oldBracketOn = AR.BracketOn;
6,276✔
1812
                WORD *oldBrackBuf = AT.BrackBuf;
6,276✔
1813
                WORD oldbracketindexflag = AT.bracketindexflag;
6,276✔
1814

1815
                /* For redefine statements. */
1816
                if ( AC.numpfirstnum > 0 ) {
6,276✔
1817
                        for ( j = 0; j < AC.numpfirstnum; j++ ) {
42✔
1818
                                AC.inputnumbers[j] = -1;
21✔
1819
                        }
1820
                }
1821

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

1933
                This operation is moved to the beginning of each block, see PreProcessor
1934
                in pre.c.
1935

1936
                 #] Slave : 
1937
*/
1938
                if ( PF.log ) {
6,276✔
1939
                        UBYTE lbuf[24];
×
1940
                        NumToStr(lbuf,AC.CModule);
×
1941
                        fprintf(stderr,"[%d|%s] Endsort,Collect,Broadcast done\n",PF.me,lbuf);
×
1942
                        fflush(stderr);
×
1943
                }
1944
        }
1945
        return(0);
1946
}
1947

1948
/*
1949
                 #] PF_Processor : 
1950
          #] proces.c : 
1951
          #[ startup :, prepro & compile
1952
                 #[ PF_Init :
1953
*/
1954

1955
/**
1956
 * All the library independent stuff.
1957
 * PF_LibInit() should do all library dependent initializations.
1958
 *
1959
 * @param  argc  pointer to the number of arguments.
1960
 * @param  argv  pointer to the arguments.
1961
 * @return       0 if OK, nonzero on error.
1962
 */
1963
int PF_Init(int *argc, char ***argv)
1,041✔
1964
{
1965
/*
1966
                this should definitely be somewhere else ...
1967
*/
1968
        PF_CurrentBracket = 0;
1,041✔
1969

1970
        PF.numtasks = 0; /* number of tasks, is determined in PF_LibInit ! */
1,041✔
1971
        PF.numsbufs = 2; /* might be changed by the environment variable on the master ! */
1,041✔
1972
        PF.numrbufs = 2; /* might be changed by the environment variable on the master ! */
1,041✔
1973

1974
        PF_LibInit(argc,argv);
1,041✔
1975
        PF_RealTime(PF_RESET);
1,041✔
1976

1977
        PF.log = 0;
1,041✔
1978
        PF.parallel = 0;
1,041✔
1979
        PF_statsinterval = 10;
1,041✔
1980
        PF.rhsInParallel=1;
1,041✔
1981
        PF.exprbufsize=4096;/*in WORDs*/
1,041✔
1982

1983
#ifdef PF_WITHGETENV
1984
        if ( PF.me == MASTER ) {
1,041✔
1985
                char *c;
261✔
1986
/*
1987
                        get these from the environment at the moment should be in setfile/tail
1988
*/
1989
                if ( ( c = getenv("PF_LOG") ) != 0 ) {
261✔
1990
                        if ( *c ) PF.log = (int)atoi(c);
×
1991
                        else PF.log = 1;
×
1992
                        fprintf(stderr,"[%d] changing PF.log to %d\n",PF.me,PF.log);
×
1993
                        fflush(stderr);
×
1994
                }
1995
                if ( ( c = (char*)getenv("PF_RBUFS") ) != 0 ) {
261✔
1996
                        PF.numrbufs = (int)atoi(c);
×
1997
                        fprintf(stderr,"[%d] changing numrbufs to: %d\n",PF.me,PF.numrbufs);
×
1998
                        fflush(stderr);
×
1999
                }
2000
                if ( ( c = (char*)getenv("PF_SBUFS") ) != 0 ) {
261✔
2001
                        PF.numsbufs = (int)atoi(c);
×
2002
                        fprintf(stderr,"[%d] changing numsbufs to: %d\n",PF.me,PF.numsbufs);
×
2003
                        fflush(stderr);
×
2004
                }
2005
                if ( PF.numsbufs > 10 ) PF.numsbufs = 10;
261✔
2006
                if ( PF.numsbufs <  1 ) PF.numsbufs = 1;
261✔
2007
                if ( PF.numrbufs >  2 ) PF.numrbufs = 2;
261✔
2008
                if ( PF.numrbufs <  1 ) PF.numrbufs = 1;
261✔
2009

2010
                if ( ( c = getenv("PF_STATS") ) ) {
261✔
2011
                        UBYTE lbuf[24];
×
2012
                        PF_statsinterval = (int)atoi(c);
×
2013
                        NumToStr(lbuf,PF_statsinterval);
×
2014
                        fprintf(stderr,"[%d] changing PF_statsinterval to %s\n",PF.me,lbuf);
×
2015
                        fflush(stderr);
×
2016
                        if ( PF_statsinterval < 1 ) PF_statsinterval = 10;
×
2017
                }
2018
        }
2019
#endif
2020
/*
2021
          #[ Broadcast settings from getenv: could also be done in PF_DoSetup
2022
*/
2023
        if ( PF.me == MASTER ) {
1,041✔
2024
                PF_PreparePack();
261✔
2025
                PF_Pack(&PF.log,1,PF_INT);
261✔
2026
                PF_Pack(&PF.numrbufs,1,PF_WORD);
261✔
2027
                PF_Pack(&PF.numsbufs,1,PF_WORD);
261✔
2028
        }
2029
        PF_Broadcast();
1,041✔
2030
        if ( PF.me != MASTER ) {
1,041✔
2031
                PF_Unpack(&PF.log,1,PF_INT);
780✔
2032
                PF_Unpack(&PF.numrbufs,1,PF_WORD);
780✔
2033
                PF_Unpack(&PF.numsbufs,1,PF_WORD);
780✔
2034
                if ( PF.log ) {
780✔
2035
                        fprintf(stderr, "[%d] log=%d rbufs=%d sbufs=%d\n",
×
2036
                                PF.me, PF.log, PF.numrbufs, PF.numsbufs);
2037
                        fflush(stderr);
×
2038
                }
2039
        }
2040
/*
2041
          #] Broadcast settings from getenv: 
2042
*/
2043
        return(0);
1,041✔
2044
}
2045
/*
2046
                 #] PF_Init : 
2047
                 #[ PF_Terminate :
2048
*/
2049

2050
/**
2051
 * Performs the finalization of ParFORM.
2052
 * To be called by Terminate().
2053
 *
2054
 * @param  error  an error code.
2055
 * @return        0 if OK, nonzero on error.
2056
 */
2057
int PF_Terminate(int errorcode)
1,041✔
2058
{
2059
        return PF_LibTerminate(errorcode);
1,041✔
2060
}
2061

2062
/*
2063
                 #] PF_Terminate : 
2064
                 #[ PF_GetSlaveTimes :
2065
*/
2066

2067
/**
2068
 * Returns the total CPU time of all slaves together.
2069
 * This function must be called on the master and all slaves.
2070
 *
2071
 * @return  on the master, the sum of CPU times on all slaves.
2072
 */
2073
LONG PF_GetSlaveTimes(void)
2,105✔
2074
{
2075
        LONG slavetimes = 0;
2,105✔
2076
        LONG t = PF.me == MASTER ? 0 : AM.SumTime + TimeCPU(1);
2,105✔
2077
        MPI_Reduce(&t, &slavetimes, 1, PF_LONG, MPI_SUM, MASTER, PF_COMM);
2,105✔
2078
        return slavetimes;
2,105✔
2079
}
2080

2081
/*
2082
                 #] PF_GetSlaveTimes : 
2083
          #] startup : 
2084
          #[ PF_BroadcastNumber :
2085
*/
2086

2087
/**
2088
 * Broadcasts a LONG value from the master to the all slaves.
2089
 *
2090
 * @param  x  the number to be broadcast (set on the master).
2091
 * @return    the synchronised result.
2092
 */
2093
LONG PF_BroadcastNumber(LONG x)
3,167✔
2094
{
2095
#ifdef PF_DEBUG_BCAST_LONG
2096
        if ( PF.me == MASTER ) {
2097
                MesPrint(">> Broadcast LONG: %l", x);
2098
        }
2099
#endif
2100
        PF_Bcast(&x, sizeof(LONG));
3,167✔
2101
        return x;
3,167✔
2102
}
2103

2104
/*
2105
          #] PF_BroadcastNumber : 
2106
          #[ PF_BroadcastBuffer :
2107
*/
2108

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

2151
/*
2152
          #] PF_BroadcastBuffer : 
2153
          #[ PF_BroadcastString :
2154
*/
2155

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

2177
                if ( MASTER == PF.me ) { /*Pack str*/
24✔
2178
/*
2179
                                initialize buffers
2180
*/
2181
                        if ( PF_PreparePack() != 0 ) Terminate(-1);
6✔
2182
                        if ( ( clength = PF_PackString(cstr) ) <0  ) Terminate(-1);
6✔
2183
                }
2184
                PF_Broadcast();
24✔
2185

2186
                if ( MASTER != PF.me ) {
24✔
2187
/*
2188
                                Slave - unpack received string
2189
                                For slaves buffers are initialised automatically.
2190
*/
2191
                        if ( ( clength = PF_UnpackString(cstr) ) < 0 ) Terminate(-1);
18✔
2192
                }
2193
        } while ( cstr[clength-1] != '\0' );
24✔
2194
        return (0);
24✔
2195
}
2196

2197
/*
2198
          #] PF_BroadcastString : 
2199
          #[ PF_BroadcastPreDollar :
2200
*/
2201

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

2236
                        PF_maxDollarChunkSize is the maximal number of items fitted to
2237
                        the buffer. It is calculated in PF_LibInit() in mpi.c.
2238
                        PF_maxDollarChunkSize is calculated for the first step, when
2239
                        two fields (numterms and newsize, see below) are already packed.
2240
                        For simplicity, this value is used also for all steps, in
2241
                        despite  of it is        a bit less than maximally available space.
2242
*/
2243
                WORD *thechunk = *dbuffer;
8✔
2244

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

2316
/*
2317
          #] PF_BroadcastPreDollar : 
2318
          #[ Synchronization of modified dollar variables :
2319
                 #[ Helper functions :
2320
                        #[ dollarlen :
2321
*/
2322

2323
/**
2324
 * Returns the size of \a terms in WORDs, not including the null terminator.
2325
 */
2326
static inline LONG dollarlen(const WORD *terms)
56✔
2327
{
2328
        const WORD *p = terms;
56✔
2329
        while ( *p ) p += *p;
124✔
2330
        return p - terms;  /* Not including the null terminator. */
56✔
2331
}
2332

2333
/*
2334
                        #] dollarlen : 
2335
                        #[ dollar_mod_type :
2336
*/
2337

2338
/**
2339
 * Returns the module option type of a dollar variable specified by \a index.
2340
 * If no module option is given for the variable, this function returns -1.
2341
 */
2342
static inline WORD dollar_mod_type(WORD index)
572✔
2343
{
2344
        int i;
572✔
2345
        for ( i = 0; i < NumModOptdollars; i++ )
772✔
2346
                if ( ModOptdollars[i].number == index ) break;
644✔
2347
        if ( i >= NumModOptdollars ) return -1;
572✔
2348
        return ModOptdollars[i].type;
245✔
2349
}
2350

2351

2352
/*
2353
                        #] dollar_mod_type : 
2354
                 #] Helper functions : 
2355
                 #[ PF_CollectModifiedDollars :
2356
*/
2357

2358
/*
2359
                        #[ dollar_to_be_collected :
2360
*/
2361

2362
/**
2363
 * Returns true if the dollar variable specified by \a index has to be collected
2364
 * from each slave to the master, i.e., declared as MODSUM, MODMAX or MODMIN.
2365
 */
2366
static inline int dollar_to_be_collected(WORD index)
245✔
2367
{
2368
        switch ( dollar_mod_type(index) ) {
490✔
2369
                case MODSUM:
2370
                case MODMAX:
2371
                case MODMIN:
2372
                        return 1;
2373
                default:
124✔
2374
                        return 0;
124✔
2375
        }
2376
}
2377

2378
/*
2379
                        #] dollar_to_be_collected : 
2380
                        #[ copy_dollar :
2381
*/
2382

2383
/**
2384
 * Copy the data given by \a type, \a where and \a size to a dollar variable
2385
 * specified by \a index.
2386
 */
2387
static inline void copy_dollar(WORD index, WORD type, const WORD *where, LONG size)
11✔
2388
{
2389
        DOLLARS d = Dollars + index;
11✔
2390

2391
        CleanDollarFactors(d);
11✔
2392

2393
        if ( type != DOLZERO && where != NULL && where != &AM.dollarzero && where[0] != 0 && size > 0 ) {
11✔
2394
                if ( size > d->size || size < d->size / 4 ) {  /* Reallocate if not enough or too much. */
10✔
2395
                        if ( d->where && d->where != &AM.dollarzero )
10✔
2396
                                M_free(d->where, "old content of dollar");
10✔
2397
                        d->where = Malloc1(sizeof(WORD) * size, "copy buffer to dollar");
10✔
2398
                        d->size  = size;
10✔
2399
                }
2400
                d->type  = type;
10✔
2401
                WCOPY(d->where, where, size);
60✔
2402
        }
2403
        else {
2404
                if ( d->where && d->where != &AM.dollarzero )
1✔
2405
                        M_free(d->where, "old content of dollar");
1✔
2406
                d->type  = DOLZERO;
1✔
2407
                d->where = &AM.dollarzero;
1✔
2408
                d->size  = 0;
1✔
2409
        }
2410
}
11✔
2411

2412
/*
2413
                        #] copy_dollar : 
2414
                        #[ compare_two_expressions :
2415
*/
2416

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

2473
/*
2474
                        #] compare_two_expressions : 
2475
                        #[ Variables :
2476
*/
2477

2478
typedef struct {
2479
        VectorStruct(WORD) buf;
2480
        LONG size;
2481
        WORD type;
2482
        PADPOINTER(1,0,1,0);
2483
} dollar_buf;
2484

2485
/* Buffers used to store data for each variable from each slave. */
2486
static Vector(dollar_buf, dollar_slave_bufs);
2487

2488
/*
2489
                        #] Variables : 
2490
*/
2491

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

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

2608
                                        CBUF *C = cbuf + AM.rbufnum;
1✔
2609
                                        WORD *oldwork = AT.WorkPointer, *oldcterm = AN.cTerm;
1✔
2610
                                        WORD olddefer = AR.DeferFlag, oldnumlhs = AR.Cnumlhs, oldnumrhs = C->numrhs;
1✔
2611

2612
                                        LONG size;
1✔
2613
                                        WORD type, *dbuf;
1✔
2614

2615
                                        AN.cTerm = 0;
1✔
2616
                                        AR.DeferFlag = 0;
1✔
2617

2618
                                        if ( ((WORD *)((UBYTE *)AT.WorkPointer + AM.MaxTer)) > AT.WorkTop ) {
1✔
2619
                                                err = -1;
×
2620
                                                goto cleanup;
×
2621
                                                MesWork();
2622
                                        }
2623

2624
                                        if ( NewSort(BHEAD0) ) {
1✔
2625
                                                err = -1;
×
2626
                                                goto cleanup;
×
2627
                                        }
2628
                                        if ( NewSort(BHEAD0) ) {
1✔
2629
                                                LowerSortLevel();
×
2630
                                                err = -1;
×
2631
                                                goto cleanup;
×
2632
                                        }
2633

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

2654
                                        size = EndSort(BHEAD (WORD *)&dbuf, 2);
1✔
2655
                                        if ( size < 0 ) {
1✔
2656
                                                LowerSortLevel();
×
2657
                                                err = -1;
×
2658
                                                goto cleanup;
×
2659
                                        }
2660
                                        LowerSortLevel();
1✔
2661

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

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

2745
/*
2746
                 #] PF_CollectModifiedDollars : 
2747
                 #[ PF_BroadcastModifiedDollars :
2748
*/
2749

2750
/*
2751
                        #[ dollar_to_be_broadcast :
2752
*/
2753

2754
/**
2755
 * Returns true if the dollar variable specified by \a index has to be broadcast
2756
 * from the master to the all slaves, i.e., non-local.
2757
 */
2758
static inline int dollar_to_be_broadcast(WORD index)
316✔
2759
{
2760
        switch ( dollar_mod_type(index) ) {
504✔
2761
                case MODLOCAL:
2762
                        return 0;
2763
                default:
216✔
2764
                        return 1;
216✔
2765
        }
2766
}
2767

2768
/*
2769
                        #] dollar_to_be_broadcast : 
2770
*/
2771

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

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

2897
/*
2898
                 #] PF_BroadcastModifiedDollars : 
2899
          #] Synchronization of modified dollar variables : 
2900
          #[ Synchronization of redefined preprocessor variables :
2901
                 #[ Variables :
2902
*/
2903

2904
/* A buffer used in receivers. */
2905
static Vector(UBYTE, prevarbuf);
2906

2907
/*
2908
                 #] Variables : 
2909
                 #[ PF_PackRedefinedPreVars :
2910
*/
2911

2912
/**
2913
 * Packs information of redefined preprocessor variables into the long single
2914
 * pack buffer, with the corresponding value in AC.inputnumbers.
2915
 *
2916
 * The potentially redefined preprocessor variables are given in AC.pfirstnum,
2917
 * and the number of them is given by AC.numpfirstnum. For an actually redefined
2918
 * variable, the corresponding value in AC.inputnumbers is non-negative.
2919
 */
2920
static void PF_PackRedefinedPreVars(void)
21✔
2921
{
2922
        int i;
21✔
2923
        /* First, pack the number of redefined preprocessor variables. */
2924
        int nredefs = 0;
21✔
2925
        for ( i = 0; i < AC.numpfirstnum; i++ )
42✔
2926
                if ( AC.inputnumbers[i] >= 0 ) nredefs++;
21✔
2927
        PF_LongSinglePack(&nredefs, 1, PF_INT);
21✔
2928
        /* Then, pack each variable. */
2929
        for ( i = 0; i < AC.numpfirstnum; i++ )
63✔
2930
                if ( AC.inputnumbers[i] >= 0) {
21✔
2931
                        WORD index = AC.pfirstnum[i];
7✔
2932
                        UBYTE *value = PreVar[index].value;
7✔
2933
                        int bytes = strlen((char *)value);
7✔
2934
                        PF_LongSinglePack(&index, 1, PF_WORD);
7✔
2935
                        PF_LongSinglePack(&bytes, 1, PF_INT);
7✔
2936
                        PF_LongSinglePack(value, bytes, PF_BYTE);
7✔
2937
                        PF_LongSinglePack(&AC.inputnumbers[i], 1, PF_LONG);
7✔
2938
        }
2939
}
21✔
2940

2941
/*
2942
                 #] PF_PackRedefinedPreVars : 
2943
                 #[ PF_UnpackRedefinedPreVars :
2944
*/
2945

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

2986
/*
2987
                 #] PF_UnpackRedefinedPreVars : 
2988
                 #[ PF_BroadcastRedefinedPreVars :
2989
*/
2990

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

3066
/*
3067
                 #] PF_BroadcastRedefinedPreVars : 
3068
          #] Synchronization of redefined preprocessor variables : 
3069
          #[ Preprocessor Inside instruction :
3070
                 #[ Variables :
3071
*/
3072

3073
/* Saved values of AC.RhsExprInModuleFlag, PotModdollars and AC.pfirstnum. */
3074
static WORD oldRhsExprInModuleFlag;
3075
static Vector(WORD, oldPotModdollars);
3076
static Vector(WORD, oldpfirstnum);
3077

3078
/*
3079
                 #] Variables : 
3080
                 #[ PF_StoreInsideInfo :
3081
*/
3082

3083
/*
3084
 * Saves the current values of AC.RhsExprInModuleFlag, PotModdollars
3085
 * and AC.pfirstnum.
3086
 *
3087
 * Called by DoInside().
3088
 *
3089
 * @return  0  if OK, nonzero on error.
3090
 */
3091
int PF_StoreInsideInfo(void)
40✔
3092
{
3093
        int i;
40✔
3094
        oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
40✔
3095
        VectorClear(oldPotModdollars);
40✔
3096
        for ( i = 0; i < NumPotModdollars; i++ )
40✔
3097
                VectorPushBack(oldPotModdollars, PotModdollars[i]);
×
3098
        VectorClear(oldpfirstnum);
40✔
3099
        for ( i = 0; i < AC.numpfirstnum; i++ )
40✔
3100
                VectorPushBack(oldpfirstnum, AC.pfirstnum[i]);
×
3101
        return 0;
40✔
3102
}
3103

3104
/*
3105
                 #] PF_StoreInsideInfo : 
3106
                 #[ PF_RestoreInsideInfo :
3107
*/
3108

3109
/*
3110
 * Restores the saved values of AC.RhsExprInModuleFlag, PotModdollars
3111
 * and AC.pfirstnum.
3112
 *
3113
 * Called by DoEndInside().
3114
 *
3115
 * @return  0  if OK, nonzero on error.
3116
 */
3117
int PF_RestoreInsideInfo(void)
40✔
3118
{
3119
        int i;
40✔
3120
        AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
40✔
3121
        NumPotModdollars = VectorSize(oldPotModdollars);
40✔
3122
        for ( i = 0; i < NumPotModdollars; i++ )
40✔
3123
                PotModdollars[i] = VectorPtr(oldPotModdollars)[i];
×
3124
        AC.numpfirstnum = VectorSize(oldpfirstnum);
40✔
3125
        for ( i = 0; i < AC.numpfirstnum; i++ )
40✔
3126
                AC.pfirstnum[i] = VectorPtr(oldpfirstnum)[i];
×
3127
        return 0;
40✔
3128
}
3129

3130
/*
3131
                 #] PF_RestoreInsideInfo : 
3132
          #] Preprocessor Inside instruction : 
3133
          #[ PF_BroadcastCBuf :
3134
*/
3135

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

3243
/*
3244
          #] PF_BroadcastCBuf : 
3245
          #[ PF_BroadcastExpFlags :
3246
*/
3247

3248
/**
3249
 * Broadcasts AR.expflags and several properties of each expression,
3250
 * e.g., e->vflags, from the master to all slaves.
3251
 *
3252
 * @return 0 if OK, nonzero on error.
3253
 */
3254
int PF_BroadcastExpFlags(void)
2,025✔
3255
{
3256
        WORD i;
2,025✔
3257
        EXPRESSIONS e;
2,025✔
3258
        if ( PF.me == MASTER ) {
2,025✔
3259
/*
3260
                 #[ Master :
3261
*/
3262
                PF_PrepareLongMultiPack();
507✔
3263
                PF_LongMultiPack(&AR.expflags, 1, PF_WORD);
507✔
3264
                for ( i = 0; i < NumExpressions; i++ ) {
3,596✔
3265
                        e = &Expressions[i];
2,582✔
3266
                        PF_LongMultiPack(&e->counter,    1, PF_WORD);
2,582✔
3267
                        PF_LongMultiPack(&e->vflags,     1, PF_WORD);
2,582✔
3268
                        PF_LongMultiPack(&e->uflags,     1, PF_WORD);
2,582✔
3269
                        PF_LongMultiPack(&e->numdummies, 1, PF_WORD);
2,582✔
3270
                        PF_LongMultiPack(&e->numfactors, 1, PF_WORD);
2,582✔
3271
#ifdef PF_DEBUG_BCAST_EXPRFLAGS
3272
                        MesPrint(">> Broadcast ExprFlags: %s", AC.exprnames->namebuffer + e->name);
3273
#endif
3274
                }
3275
/*
3276
                 #] Master : 
3277
*/
3278
        }
3279
        if ( PF_LongMultiBroadcast() ) return -1;
2,025✔
3280
        if ( PF.me != MASTER ) {
2,025✔
3281
/*
3282
                 #[ Slave :
3283
*/
3284
                PF_LongMultiUnpack(&AR.expflags, 1, PF_WORD);
1,518✔
3285
                for ( i = 0; i < NumExpressions; i++ ) {
10,782✔
3286
                        e = &Expressions[i];
7,746✔
3287
                        PF_LongMultiUnpack(&e->counter,    1, PF_WORD);
7,746✔
3288
                        PF_LongMultiUnpack(&e->vflags,     1, PF_WORD);
7,746✔
3289
                        PF_LongMultiUnpack(&e->uflags,     1, PF_WORD);
7,746✔
3290
                        PF_LongMultiUnpack(&e->numdummies, 1, PF_WORD);
7,746✔
3291
                        PF_LongMultiUnpack(&e->numfactors, 1, PF_WORD);
7,746✔
3292
                }
3293
/*
3294
                 #] Slave : 
3295
*/
3296
        }
3297
        return 0;
3298
}
3299

3300
/*
3301
          #] PF_BroadcastExpFlags : 
3302
          #[ PF_SetScratch :
3303
*/
3304

3305
/**
3306
 * Same as SetScratch() except it always fills the buffer from the given position.
3307
 *
3308
 * @param  f         the file handle.
3309
 * @param  position  the position to be loaded into the buffer.
3310
 */
3311
static void PF_SetScratch(FILEHANDLE *f,POSITION *position)
263✔
3312
{
3313
        if(
263✔
3314
                        ( f->handle >= 0) && ISGEPOS(*position,f->POposition) &&
263✔
3315
                        ( ISGEPOSINC(*position,f->POposition,(f->POfull-f->PObuffer)*sizeof(WORD)) ==0 )
×
3316
                )/*position is inside the buffer! SetScratch() will do nothing.*/
3317
                        f->POfull=f->PObuffer;/*force SetScratch() to re-read the position from the beginning:*/
×
3318
        SetScratch(f,position);
263✔
3319
}
263✔
3320

3321
/*
3322
          #] PF_SetScratch : 
3323
          #[ PF_pushScratch :
3324
*/
3325

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

3361
/*
3362
          #] PF_pushScratch : 
3363
          #[ Broadcasting RHS expressions :
3364
                 #[ PF_WalkThroughExprMaster :
3365
        Returns <=0 if the expression is ready, or dl+1;
3366
*/
3367

3368
static int PF_WalkThroughExprMaster(FILEHANDLE *curfile, int dl)
11,220✔
3369
{
3370
        LONG l=0;
11,220✔
3371
        for(;;){
2,045,030✔
3372
                if(curfile->POfull-curfile->POfill < dl){
2,045,030✔
3373
                        POSITION pos;
×
3374
                        SeekScratch(curfile,&pos);
×
3375
                        PF_SetScratch(curfile,&pos);
×
3376
                }/*if(curfile->POfull-curfile->POfill < dl)*/
3377
                curfile->POfill+=dl;
2,045,030✔
3378
                l+=dl;
2,045,030✔
3379
                if( l >= PF.exprbufsize){
2,045,030✔
3380
                        if( l == PF.exprbufsize){
10,910✔
3381
                                if( *(curfile->POfill) == 0)/*expression is ready*/
3✔
3382
                                        return(0);
3383
                                }
3384
                        l-=PF.exprbufsize;
10,910✔
3385
                        curfile->POfill-=l;
10,910✔
3386
                        return l+1;
10,910✔
3387
                }
3388

3389
                dl=*(curfile->POfill);
2,034,120✔
3390
                if(dl == 0)
2,034,120✔
3391
                        return l-PF.exprbufsize;
310✔
3392

3393
                if(dl<0){/*compressed term*/
2,033,810✔
3394
                        if(curfile->POfull-curfile->POfill < 1){
5,553✔
3395
                                POSITION pos;
×
3396
                                SeekScratch(curfile,&pos);
×
3397
                                PF_SetScratch(curfile,&pos);
×
3398
                        }/*if(curfile->POfull-curfile->POfill < 1)*/
3399
                        dl=*(curfile->POfill+1)+2;
5,553✔
3400
                }/*if(*(curfile->POfill)<0)*/
3401
        }/*for(;;)*/
3402
}
3403

3404
/*
3405
                 #] PF_WalkThroughExprMaster : 
3406
                 #[ PF_WalkThroughExprSlave :
3407
        Returns <=0 if the expression is ready, or dl+1;
3408
*/
3409

3410
static int PF_WalkThroughExprSlave(FILEHANDLE *curfile, LONG *counter, int dl)
33,660✔
3411
{
3412
        LONG l=0;
33,660✔
3413
        for(;;){
6,135,080✔
3414
                if(curfile->POstop-curfile->POfill < dl){
6,135,080✔
3415
                        if(PF_pushScratch(curfile))
×
3416
                                return(-PF.exprbufsize-1);
×
3417
                }
3418
                curfile->POfill+=dl;
6,135,080✔
3419
                curfile->POfull=curfile->POfill;
6,135,080✔
3420
                l+=dl;
6,135,080✔
3421
                if( l >= PF.exprbufsize){
6,135,080✔
3422
                        if( l == PF.exprbufsize){
32,730✔
3423
                                /*
3424
                                 * This access is valid because PF.exprbufsize+1 WORDs are
3425
                                 * broadcasted, this shortcut is not mandatory though. (TU 15 Sep 2011)
3426
                                 */
3427
                                if( *(curfile->POfill) == 0)/*expression is ready*/
9✔
3428
                                        return(0);
3429
                                }
3430
                        l-=PF.exprbufsize;
32,730✔
3431
                        curfile->POfill-=l;
32,730✔
3432
                        curfile->POfull=curfile->POfill;
32,730✔
3433
                        return l+1;
32,730✔
3434
                }
3435

3436
                dl=*(curfile->POfill);
6,102,350✔
3437
                if(dl == 0)
6,102,350✔
3438
                        return l-PF.exprbufsize;
930✔
3439
                (*counter)++;
6,101,420✔
3440
                if(dl<0){/*compressed term*/
6,101,420✔
3441
                        if(curfile->POstop-curfile->POfill < 1){
16,659✔
3442
                                if(PF_pushScratch(curfile))
×
3443
                                        return(-PF.exprbufsize-1);
×
3444
                        }
3445
                        /*
3446
                         * This access is always valid because PF.exprbufsize+1 WORDs are
3447
                         * broadcasted. (TU 15 Sep 2011)
3448
                         */
3449
                        dl=*(curfile->POfill+1)+2;
16,659✔
3450
                }/*if(*(curfile->POfill)<0)*/
3451
        }/*for(;;)*/
3452
}
3453

3454
/*
3455
                 #] PF_WalkThroughExprSlave : 
3456
                 #[ PF_rhsBCastMaster :
3457
*/
3458

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

3490
/*
3491
                 #] PF_rhsBCastMaster : 
3492
                 #[ PF_rhsBCastSlave :
3493
*/
3494

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

3536
/*
3537
                 #] PF_rhsBCastSlave : 
3538
                 #[ PF_BroadcastExpr :
3539
*/
3540

3541
/**
3542
 * Broadcasts an expression from the master to the all slaves.
3543
 *
3544
 * @param  e     The expression to be broadcast.
3545
 * @param  file  The file in which the expression is sitting.
3546
 * @return       0 if OK, nonzero on error.
3547
 */
3548
int PF_BroadcastExpr(EXPRESSIONS e, FILEHANDLE *file)
1,240✔
3549
{
3550
        if ( PF.me == MASTER ) {
1,240✔
3551
                if ( PF_rhsBCastMaster(file, e) ) return -1;
310✔
3552
#ifdef PF_DEBUG_BCAST_RHSEXPR
3553
                MesPrint(">> Broadcast RhsExpr: %s", AC.exprnames->namebuffer + e->name);
3554
#endif
3555
        }
3556
        else {
3557
                POSITION pos;
930✔
3558
                SetEndHScratch(file, &pos);
930✔
3559
                e->onfile = pos;
930✔
3560
                if ( PF_rhsBCastSlave(file, e) ) return -1;
930✔
3561
        }
3562
        return 0;
3563
}
3564

3565
/*
3566
                 #] PF_BroadcastExpr : 
3567
                 #[ PF_BroadcastRHS :
3568
*/
3569

3570
/**
3571
 * Broadcasts expressions appearing in the right-hand side from
3572
 * the master to the all slaves.
3573
 *
3574
 * @return  0 if OK, nonzero on error.
3575
 */
3576
int PF_BroadcastRHS(void)
200✔
3577
{
3578
        int i;
200✔
3579
        for ( i = 0; i < NumExpressions; i++ ) {
2,520✔
3580
                EXPRESSIONS e = &Expressions[i];
2,320✔
3581
                if ( !(e->vflags & ISINRHS) ) continue;
2,320✔
3582
                switch ( e->status ) {
1,200✔
3583
                        case LOCALEXPRESSION:
1,152✔
3584
                        case SKIPLEXPRESSION:
3585
                        case DROPLEXPRESSION:
3586
                        case GLOBALEXPRESSION:
3587
                        case SKIPGEXPRESSION:
3588
                        case DROPGEXPRESSION:
3589
                        case HIDELEXPRESSION:
3590
                        case HIDEGEXPRESSION:
3591
                        case INTOHIDELEXPRESSION:
3592
                        case INTOHIDEGEXPRESSION:
3593
                                if ( PF_BroadcastExpr(e, AR.infile) ) return -1;
1,152✔
3594
                                break;
3595
                        case HIDDENLEXPRESSION:
48✔
3596
                        case HIDDENGEXPRESSION:
3597
                        case DROPHLEXPRESSION:
3598
                        case DROPHGEXPRESSION:
3599
                        case UNHIDELEXPRESSION:
3600
                        case UNHIDEGEXPRESSION:
3601
                                if ( PF_BroadcastExpr(e, AR.hidefile) ) return -1;
48✔
3602
                                break;
3603
                }
3604
        }
2,320✔
3605
        if ( PF.me != MASTER )
200✔
3606
                UpdatePositions();
150✔
3607
        return 0;
3608
}
3609

3610
/*
3611
                 #] PF_BroadcastRHS : 
3612
          #] Broadcasting RHS expressions : 
3613
          #[ InParallel mode :
3614
                 #[ PF_InParallelProcessor :
3615
*/
3616

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

3703
                        /* For redefine statements. */
3704
                        if ( AC.numpfirstnum > 0 ) {
1✔
3705
                                int j;
3706
                                for ( j = 0; j < AC.numpfirstnum; j++ ) {
×
3707
                                        AC.inputnumbers[j] = -1;
×
3708
                                }
3709
                        }
3710

3711
                        if(PF_DoOneExpr())/*the processor*/
1✔
3712
                                return(-1);
3713
                        if(PF_Wait4MasterIP(PF_DATA_MSGTAG))
1✔
3714
                                return(-1);
3715
                        if(PF_Slave2MasterIP(PF.me))/*both master and slave*/
1✔
3716
                                return(-1);
3717
                        AT.WorkPointer=oldwork;
1✔
3718
                }/*if(tag == PF_DATA_MSGTAG)*/
3719
        }while(tag!=PF_EMPTY_MSGTAG);
4✔
3720
        PF.exprtodo=-1;
3✔
3721
        return(0);
3✔
3722
}/*PF_InParallelProcessor*/
3723

3724
/*
3725
                 #] PF_InParallelProcessor : 
3726
                 #[ PF_Wait4MasterIP :
3727
*/
3728

3729
static int PF_Wait4MasterIP(int tag)
4✔
3730
{
3731
        int follow = 0;
4✔
3732
        LONG cpu,space = 0;
4✔
3733

3734
        if(PF.log){
4✔
3735
                fprintf(stderr,"[%d] Starting to send to Master\n",PF.me);
×
3736
                fflush(stderr);
×
3737
        }
3738

3739
        PF_PreparePack();
4✔
3740
        cpu = TimeCPU(1);
4✔
3741
        PF_Pack(&cpu               ,1,PF_LONG);
4✔
3742
        PF_Pack(&space             ,1,PF_LONG);
4✔
3743
        PF_Pack(&PF_linterms       ,1,PF_LONG);
4✔
3744
        PF_Pack(&(AM.S0->GenTerms) ,1,PF_LONG);
4✔
3745
        PF_Pack(&(AM.S0->TermsLeft),1,PF_LONG);
4✔
3746
        PF_Pack(&follow            ,1,PF_INT );
4✔
3747

3748
        if(PF.log){
4✔
3749
                fprintf(stderr,"[%d] Now sending with tag = %d\n",PF.me,tag);
×
3750
                fflush(stderr);
×
3751
        }
3752

3753
        PF_Send(MASTER, tag);
4✔
3754

3755
        if(PF.log){
4✔
3756
                fprintf(stderr,"[%d] returning from send\n",PF.me);
×
3757
                fflush(stderr);
×
3758
        }
3759
        return(0);
4✔
3760
}
3761
/*
3762
                 #] PF_Wait4MasterIP : 
3763
                 #[ PF_DoOneExpr :
3764
*/
3765

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

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

3839
                                AR.DeferFlag = AC.ComDefer;
1✔
3840

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

3911
                                fout->POfull = fout->POfill;
1✔
3912
        return(0);
1✔
3913
}
3914

3915
/*
3916
                 #] PF_DoOneExpr : 
3917
                 #[ PF_Slave2MasterIP :
3918
*/
3919

3920
typedef struct bufIPstruct {
3921
        LONG i;
3922
        struct ExPrEsSiOn e;
3923
} bufIPstruct_t;
3924

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

4009
/*
4010
                 #] PF_Slave2MasterIP : 
4011
                 #[ PF_Master2SlaveIP :
4012
*/
4013

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

4052
/*
4053
                 #] PF_Master2SlaveIP : 
4054
                 #[ PF_ReadMaster :
4055
*/
4056

4057
static int PF_ReadMaster(void)/*reads directly to its scratch!*/
4✔
4058
{
4059
        bufIPstruct_t exprData;
4✔
4060
        int tag,m=MASTER;
4✔
4061
        EXPRESSIONS e;
4✔
4062
        FILEHANDLE *fi;
4✔
4063
        POSITION pos;
4✔
4064
        LONG count=0;
4✔
4065
        WORD *t;
4✔
4066
        LONG ll=0;
4✔
4067
        int l;
4✔
4068
        /*Get metadata:*/
4069
        if (PF_RawRecv(&m, &exprData,sizeof(bufIPstruct_t),&tag)!= sizeof(bufIPstruct_t))
4✔
4070
                return(-1);
4071

4072
        if(tag == PF_EMPTY_MSGTAG)/*No data, no job*/
4✔
4073
                return(tag);
4074

4075
        /*data expected, tag must be == PF_DATA_MSTAG!*/
4076
        PF.exprtodo=exprData.i;
1✔
4077
        e=Expressions + PF.exprtodo;
1✔
4078
        /*Fill in the expression data:*/
4079
/*        memcpy(e, &(exprData.e), sizeof(struct ExPrEsSiOn)); */
4080
        if ( e->status == HIDDENLEXPRESSION || e->status == HIDDENGEXPRESSION )
1✔
4081
                fi = AR.hidefile;
×
4082
        else
4083
                fi = AR.infile;
1✔
4084
        SetEndHScratch(fi,&pos);
1✔
4085
        e->onfile=AS.OldOnFile[PF.exprtodo]=pos;
1✔
4086

4087
        do{
1✔
4088
                l=PF_RecvChunkIP(fi,MASTER,PF.exprbufsize*sizeof(WORD));
1✔
4089
                if(l<0)
1✔
4090
                        return(-1);
4091
                t=fi->POfull-l/sizeof(WORD);
1✔
4092
                ll=PF_WalkThrough(t,ll,l/sizeof(WORD),&count);
1✔
4093
        }while(ll>-2);
1✔
4094
        /*Now -ll-2 is the number of "extra" elements transferred from the master.*/
4095
        fi->POfull-=-ll-2;
1✔
4096
        fi->POfill=fi->POfull;
1✔
4097
        return(PF_DATA_MSGTAG);
1✔
4098
}
4099

4100
/*
4101
                 #] PF_ReadMaster : 
4102
                 #[ PF_SendChunkIP :
4103
        thesize is in bytes. Returns the number of sent bytes or <0 on error:
4104
*/
4105

4106
static int PF_SendChunkIP(FILEHANDLE *curfile, POSITION *position, int to, LONG thesize)
2✔
4107
{
4108
        LONG l=thesize;
2✔
4109
        if(
2✔
4110
                ISLESSPOS(*position,curfile->POposition) ||
2✔
4111
                ISGEPOSINC(*position,curfile->POposition,
2✔
4112
                ((curfile->POfull-curfile->PObuffer)*sizeof(WORD)-thesize) )
4113
        ){
4114
                if(curfile->handle< 0)
2✔
4115
                        l=(curfile->POfull-curfile->PObuffer)*sizeof(WORD) - (LONG)(position->p1);
2✔
4116
                else{
4117
                        PF_SetScratch(curfile,position);
×
4118
                        if(
×
4119
                                ISGEPOSINC(*position,curfile->POposition,
×
4120
                                ((curfile->POfull-curfile->PObuffer)*sizeof(WORD)-thesize) )
4121
                                )
4122
                        l=(curfile->POfull-curfile->PObuffer)*sizeof(WORD) - (LONG)position->p1;
×
4123
                }
4124
        }
4125
        /*Now we are able to sent l bytes from the
4126
                curfile->PObuffer[position-curfile->POposition]*/
4127
        if(PF_RawSend(to,curfile->PObuffer+ (DIFBASE(*position,curfile->POposition))/sizeof(WORD),l,0))
2✔
4128
                return(-1);
4129
        return(l);
2✔
4130
}
4131

4132
/*
4133
                 #] PF_SendChunkIP : 
4134
                 #[ PF_RecvChunkIP :
4135
        thesize is in bytes. Returns the number of sent bytes or <0 on error:
4136
*/
4137

4138
static int PF_RecvChunkIP(FILEHANDLE *curfile, int from, LONG thesize)
2✔
4139
{
4140
        LONG receivedBytes;
2✔
4141

4142
        if( (LONG)((curfile->POstop - curfile->POfull)*sizeof(WORD)) < thesize )
2✔
4143
                if(PF_pushScratch(curfile))
×
4144
                        return(-1);
4145
        /*Now there is enough space from curfile->POfill to curfile->POstop*/
4146
        {/*Block:*/
4147
                int tag=0;
2✔
4148
                receivedBytes=PF_RawRecv(&from,curfile->POfull,thesize,&tag);
2✔
4149
        }/*:Block*/
4150
        if(receivedBytes >= 0 ){
2✔
4151
                curfile->POfull+=receivedBytes/sizeof(WORD);
2✔
4152
                curfile->POfill=curfile->POfull;
2✔
4153
        }/*if(receivedBytes >= 0 )*/
4154
        return(receivedBytes);
2✔
4155
}
4156

4157
/*
4158
                 #] PF_RecvChunkIP : 
4159
                 #[ PF_WalkThrough :
4160
        Returns:
4161
        >=  0 -- initial offset,
4162
                -1 -- the first element of t contains the length of the tail of compressed term,
4163
        <= -2 -- -(d+2), where d is the number of extra transferred elements.
4164
        Expects:
4165
        l -- initial offset or -1,
4166
        chunk -- number of transferred elements (not bytes!)
4167
        *count -- incremented each time a new term is found
4168
*/
4169

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

4205
/*
4206
                 #] PF_WalkThrough : 
4207
          #] InParallel mode : 
4208
          #[ PF_SendFile :
4209
*/
4210

4211
#define PF_SNDFILEBUFSIZE 4096
4212

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

4246
/*
4247
          #] PF_SendFile : 
4248
          #[ PF_RecvFile :
4249
*/
4250

4251
/**
4252
 * Receives a file from the process specified by \a from.
4253
 *
4254
 * @param  from  the source process number.
4255
 * @param  fd    the file to save the received data.
4256
 * @return       the size of received data in bytes, or -1 on error.
4257
 */
4258
int PF_RecvFile(int from, FILE *fd)
×
4259
{
4260
        size_t len=0;
×
4261
        int tag;
×
4262
        do{
×
4263
                char buf[PF_SNDFILEBUFSIZE];
×
4264
                int l;
×
4265
                        l=PF_RawRecv(&from,buf,PF_SNDFILEBUFSIZE,&tag);
×
4266
                        if(l<0)
×
4267
                                return(-1);
×
4268
                        if(tag == PF_EMPTY_MSGTAG)
×
4269
                                return(-1);
4270

4271
                        if( fwrite(buf,l,1,fd)!=1 )
×
4272
                                return(-1);
4273
                        len+=l;
×
4274
        }while(tag!=PF_ENDBUFFER_MSGTAG);
×
4275
        return(len);
×
4276
}
4277

4278
/*
4279
          #] PF_RecvFile : 
4280
          #[ Synchronised output :
4281
                 #[ Explanations :
4282
*/
4283

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

4311
/*
4312
                 #] Explanations : 
4313
                 #[ Variables :
4314
*/
4315

4316
static int errorMessageLock = 0;     /* (slaves) The lock count. See PF_MLock() and PF_MUnlock(). */
4317
static Vector(UBYTE, stdoutBuffer);  /* (slaves) The buffer for AM.StdOut. */
4318
static Vector(UBYTE, logBuffer);     /* (slaves) The buffer for AC.LogHandle. */
4319
#define recvBuffer logBuffer         /* (master) The buffer for receiving messages. */
4320

4321
/*
4322
 * If PF_ENABLE_STDOUT_BUFFERING is defined, the master performs the line buffering
4323
 * (using stdoutBuffer) at PF_WriteFileToFile().
4324
 */
4325
#ifndef PF_ENABLE_STDOUT_BUFFERING
4326
#ifdef UNIX
4327
#define PF_ENABLE_STDOUT_BUFFERING
4328
#endif
4329
#endif
4330

4331
/*
4332
                 #] Variables : 
4333
                 #[ PF_MLock :
4334
*/
4335

4336
/**
4337
 * A function called by MLOCK(ErrorMessageLock) for slaves.
4338
 */
4339
void PF_MLock(void)
231✔
4340
{
4341
        /* Only on slaves. */
4342
        if ( errorMessageLock++ > 0 ) return;
231✔
4343
        VectorClear(stdoutBuffer);
231✔
4344
        VectorClear(logBuffer);
231✔
4345
}
4346

4347
/*
4348
                 #] PF_MLock : 
4349
                 #[ PF_MUnlock :
4350
*/
4351

4352
/**
4353
 * A function called by MUNLOCK(ErrorMessageLock) for slaves.
4354
 */
4355
void PF_MUnlock(void)
231✔
4356
{
4357
        /* Only on slaves. */
4358
        if ( --errorMessageLock > 0 ) return;
231✔
4359
        if ( !VectorEmpty(stdoutBuffer) ) {
231✔
4360
                PF_RawSend(MASTER, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer), PF_STDOUT_MSGTAG);
231✔
4361
        }
4362
        if ( !VectorEmpty(logBuffer) ) {
231✔
4363
                PF_RawSend(MASTER, VectorPtr(logBuffer), VectorSize(logBuffer), PF_LOG_MSGTAG);
×
4364
        }
4365
}
4366

4367
/*
4368
                 #] PF_MUnlock : 
4369
                 #[ PF_WriteFileToFile :
4370
*/
4371

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

4469
/*
4470
                 #] PF_WriteFileToFile : 
4471
                 #[ PF_FlushStdOutBuffer :
4472
*/
4473

4474
/**
4475
 * Explicitly Flushes the buffer for the standard output on the master, which is
4476
 * used if PF_ENABLE_STDOUT_BUFFERING is defined.
4477
 */
4478
void PF_FlushStdOutBuffer(void)
×
4479
{
4480
#ifdef PF_ENABLE_STDOUT_BUFFERING
4481
        if ( PF.me == MASTER && VectorSize(stdoutBuffer) > 0 ) {
×
4482
                WriteFileToFile(AM.StdOut, VectorPtr(stdoutBuffer), VectorSize(stdoutBuffer));
×
4483
                VectorClear(stdoutBuffer);
×
4484
        }
4485
#endif
4486
}
×
4487

4488
/*
4489
                 #] PF_FlushStdOutBuffer : 
4490
                 #[ PF_ReceiveErrorMessage :
4491
*/
4492

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

4525
/*
4526
                 #] PF_ReceiveErrorMessage : 
4527
                 #[ PF_CatchErrorMessages :
4528
*/
4529

4530
/**
4531
 * Processes all incoming messages whose tag is PF_STDOUT_MSGTAG
4532
 * or PF_LOG_MSGTAG. It ensures that the next PF_Receive(src, tag, ...)
4533
 * will not receive the message with PF_STDOUT_MSGTAG or PF_LOG_MSGTAG.
4534
 *
4535
 * @param[in,out]  src  the source process.
4536
 * @param[in,out]  tag  the tag value.
4537
 */
4538
static void PF_CatchErrorMessages(int *src, int *tag)
14,727✔
4539
{
4540
        /* Only on the master. */
4541
        for (;;) {
14,807✔
4542
                int asrc = *src;
14,807✔
4543
                int atag = *tag;
14,807✔
4544
                int ret = PF_RawProbe(&asrc, &atag, NULL);
14,807✔
4545
                CHECK(ret == 0);
14,807✔
4546
                if ( atag == PF_STDOUT_MSGTAG || atag == PF_LOG_MSGTAG ) {
14,807✔
4547
                        PF_ReceiveErrorMessage(asrc, atag);
80✔
4548
                        continue;
80✔
4549
                }
4550
                *src = asrc;
14,727✔
4551
                *tag = atag;
14,727✔
4552
                break;
14,727✔
4553
        }
4554
}
14,727✔
4555

4556
/*
4557
                 #] PF_CatchErrorMessages : 
4558
                 #[ PF_CatchErrorMessagesForAll :
4559
*/
4560

4561
/**
4562
 * Calls PF_CatchErrorMessages() for all slaves and PF_ANY_MSGTAG.
4563
 * Note that it is NOT equivalent to PF_CatchErrorMessages() with PF_ANY_SOURCE.
4564
 */
4565
static void PF_CatchErrorMessagesForAll(void)
2,092✔
4566
{
4567
        /* Only on the master. */
4568
        int i;
2,092✔
4569
        for ( i = 1; i < PF.numtasks; i++ ) {
8,368✔
4570
                int src = i;
6,276✔
4571
                int tag = PF_ANY_MSGTAG;
6,276✔
4572
                PF_CatchErrorMessages(&src, &tag);
6,276✔
4573
        }
4574
}
2,092✔
4575

4576
/*
4577
                 #] PF_CatchErrorMessagesForAll : 
4578
                 #[ PF_ProbeWithCatchingErrorMessages :
4579
*/
4580

4581
/**
4582
 * Same as PF_Probe() except processing incoming messages with PF_STDOUT_MSGTAG
4583
 * and PF_LOG_MSGTAG.
4584
 *
4585
 * @param[in,out]  src  the source process. The output value is that of the actual found message.
4586
 * @return              the tag value of the next incoming message if found,
4587
 *                      0 if a nonblocking probe (input src != PF_ANY_SOURCE) did not
4588
 *                      find any messages. The negative returned value indicates an error.
4589
 */
4590
static int PF_ProbeWithCatchingErrorMessages(int *src)
19,483,900✔
4591
{
4592
        for (;;) {
19,484,000✔
4593
                int newsrc = *src;
19,484,000✔
4594
                int tag = PF_Probe(&newsrc);
19,484,000✔
4595
                if ( tag == PF_STDOUT_MSGTAG || tag == PF_LOG_MSGTAG ) {
19,484,000✔
4596
                        PF_ReceiveErrorMessage(newsrc, tag);
151✔
4597
                        continue;
151✔
4598
                }
4599
                if ( tag > 0 ) *src = newsrc;
19,483,900✔
4600
                return tag;
19,483,900✔
4601
        }
4602
}
4603

4604
/*
4605
                 #] PF_ProbeWithCatchingErrorMessages : 
4606
                 #[ PF_FreeErrorMessageBuffers :
4607
*/
4608

4609
/**
4610
 * Frees the buffers allocated for the synchronized output.
4611
 *
4612
 * Currently, not used anywhere, but could be used in PF_Terminate().
4613
 */
4614
void PF_FreeErrorMessageBuffers(void)
×
4615
{
4616
        VectorFree(stdoutBuffer);
×
4617
        VectorFree(logBuffer);
×
4618
}
×
4619

4620
/*
4621
                 #] PF_FreeErrorMessageBuffers : 
4622
          #] Synchronised output : 
4623
*/
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