1 %****************************************************************************
3 \section[LLComms.lc]{GUM Low-Level Inter-Task Communication}
5 % This module defines PVM Routines for PE-PE communication.
7 % (c) The Parade/AQUA Projects, Glasgow University, 1994-1995
8 % P. Trinder, December 5th. 1994.
10 %****************************************************************************
14 #ifdef PAR /* whole file */
17 This module defines the routines which communicate between PEs. The
18 code is based on Kevin Hammond's GRIP RTS. (@Opcodes.h@ defines
19 @PEOp1@ etc. in terms of @SendOp1@ etc.).
24 \begin{tabular}{|l|l|} \hline
25 Routine & Arguments \\ \hline
31 @SendOpV@ & variable \\
32 @SendOpNV@ & variable+ vector \\
38 First the standard include files.
41 #define NON_POSIX_SOURCE /* so says Solaris */
53 Then some miscellaneous functions.
54 @GetOpName@ returns the character-string name of any opcode.
57 char *UserPEOpNames[] = { PEOP_NAMES };
63 if (op >= MIN_PEOPS && op <= MAX_PEOPS)
64 return (UserPEOpNames[op - MIN_PEOPS]);
67 return ("Unknown PE Opcode");
71 NullException(STG_NO_ARGS)
73 fprintf(stderr,"Null_Exception: called");
76 void (*ExceptionHandler)() = NullException;
79 @trace_SendOp@ handles the tracing of messages at the OS level. If
80 tracing is on (as specified by @PETrace@, @SystemTrace@ and
81 @ReplyTrace@), then a message is printed. The opcode and address word
82 of the previous PE opcode is recorded in the variables @lastSendOp@ and
83 @lastPEaddress@. @PElastop@ is a Boolean which records whether the
84 last message sent was for a PE or an IMU.
87 rtsBool PETrace = rtsFalse, IMUTrace = rtsFalse, SystemTrace = rtsFalse, ReplyTrace = rtsFalse;
90 trace_SendOp(OPCODE op, GLOBAL_TASK_ID dest, unsigned int data1, unsigned int data2)
94 if (!ReplyTrace && op == REPLY_OK)
97 OpName = GetOpName(op);
98 /* fprintf(stderr, " %s [%x,%x] sent from %x to %x\n", OpName, data1, data2, mytid, dest);*/
103 @SendOp@ sends a 0-argument message with opcode {\em op} to
104 the global task {\em task}.
112 trace_SendOp(op, task,0,0);
114 pvm_initsend(PvmDataRaw);
115 pvm_send( task, op );
119 @SendOp1@ sends a 1-argument message with opcode {\em op}
120 to the global task {\em task}.
124 SendOp1(op, task, arg1)
129 trace_SendOp(op, task, arg1,0);
131 pvm_initsend(PvmDataRaw);
133 pvm_send( task, op );
138 @SendOp2@ is used by the FP code only.
142 SendOp2(op, task, arg1, arg2)
148 trace_SendOp(op, task, arg1, arg2);
150 pvm_initsend(PvmDataRaw);
153 pvm_send( task, op );
157 @SendOpV@ takes a variable number of arguments, as specified by {\em n}.
160 SendOpV( PP_STATS, StatsTask, 3, start_time, stop_time, sparkcount);
165 SendOpV(OPCODE op, GLOBAL_TASK_ID task, int n, ...)
173 trace_SendOp(op, task, 0, 0);
175 pvm_initsend(PvmDataRaw);
177 for (i = 0; i < n; ++i) {
178 arg = va_arg(ap, StgWord);
187 @SendOpNV@ takes a variable-size datablock, as specified by {\em
188 nelem} and a variable number of arguments, as specified by {\em
189 narg}. N.B. The datablock and the additional arguments are contiguous
190 and are copied over together. For example,
193 SendOpNV(PP_RESUME, tsoga.pe, 6, nelem, data,
194 (W_) ga.weight, (W_) ga.loc.gc.gtid, (W_) ga.loc.gc.slot,
195 (W_) tsoga.weight, (W_) tsoga.loc.gc.gtid, (W_) tsoga.loc.gc.slot);
198 Important: The variable arguments must all be StgWords.
203 SendOpNV(OPCODE op, GLOBAL_TASK_ID task, int nelem, StgWord *datablock, int narg, ...)
211 trace_SendOp(op, task, 0, 0);
212 /* fprintf(stderr,"SendOpNV: op = %x, task = %x, narg = %d, nelem = %d\n",op,task,narg,nelem); */
214 pvm_initsend(PvmDataRaw);
216 for (i = 0; i < narg; ++i) {
217 arg = va_arg(ap, StgWord);
218 /* fprintf(stderr,"SendOpNV: arg = %d\n",arg); */
221 arg = (StgWord) nelem;
224 /* for (i=0; i < nelem; ++i) fprintf(stderr, "%d ",datablock[i]); */
225 /* fprintf(stderr," in SendOpNV\n");*/
227 PutArgs(datablock, nelem);
235 @SendOpN@ take a variable size array argument, whose size is given by
236 {\em n}. For example,
239 SendOpN( PP_STATS, StatsTask, 3, stats_array);
245 SendOpN(op, task, n, args)
254 trace_SendOp(op, task, 0, 0);
256 pvm_initsend(PvmDataRaw);
264 @WaitForPEOp@ waits for a packet from global task {\em who} with the
265 opcode {\em op}. Other opcodes are handled by the standard exception handler.
268 PACKET WaitForPEOp(op, who)
275 GLOBAL_TASK_ID sender_id;
279 /* fprintf(stderr,"WaitForPEOp: op = %x, who = %x\n",op,who); */
280 while((p = pvm_recv(ANY_TASK,ANY_OPCODE)) < 0)
281 pvm_perror("WaitForPEOp: Waiting for PEOp");
283 pvm_bufinfo( p, &nbytes, &opcode, &sender_id );
285 match = (op == ANY_OPCODE || op == opcode) && (who == ANY_TASK || who == sender_id);
290 /* Handle the unexpected opcodes */
305 GLOBAL_TASK_ID sender_id;
306 pvm_bufinfo( p, &nbytes, &opcode, &sender_id );
316 GLOBAL_TASK_ID sender_id;
317 pvm_bufinfo( p, &nbytes, &opcode, &sender_id );
322 get_opcode_and_sender(p,popcode,psender_id)
325 GLOBAL_TASK_ID *psender_id;
328 pvm_bufinfo( p, &nbytes, popcode, psender_id );
333 @PEStartUp@ does the low-level comms specific startup stuff for a
334 PE. It initialises the comms system, joins the appropriate groups,
335 synchronises with the other PEs. Finally it receives from Control the
336 array of Global Task Ids.
345 long *buffer = (long *) stgMallocBytes(sizeof(long) * nPEs, "PEStartUp (buffer)");
347 = (GLOBAL_TASK_ID *) stgMallocBytes(sizeof(GLOBAL_TASK_ID) * nPEs, "PEStartUp (PEs)");
349 mytid = _my_gtid; /* Initialise PVM and get task id into global
352 /* fprintf(stderr,"PEStartup, No. PEs = %d \n", nPEs); */
353 checkComms(pvm_joingroup(PEGROUP), "PEStartup");
354 /* fprintf(stderr,"PEStartup, Joined PEGROUP\n"); */
355 checkComms(pvm_joingroup(PECTLGROUP), "PEStartup");
356 /* fprintf(stderr,"PEStartup, Joined PECTLGROUP\n"); */
357 checkComms(pvm_barrier(PECTLGROUP, nPEs + 1), "PEStartup");
358 /* fprintf(stderr,"PEStartup, Passed PECTLGROUP barrier\n"); */
360 addr = WaitForPEOp(PP_PETIDS, ANY_GLOBAL_TASK);
361 GetArgs(buffer, nPEs);
362 for (i = 0; i < nPEs; ++i) {
363 PEs[i] = (GLOBAL_TASK_ID) buffer[i];
364 /* fprintf(stderr,"PEs[%d] = %x \n", i, PEs[i]); */
371 @PEShutdown@ does the low-level comms-specific shutdown stuff for a
372 single PE. It leaves the groups and then exits from pvm.
376 PEShutDown(STG_NO_ARGS)
378 checkComms(pvm_lvgroup(PEGROUP),"PEShutDown");
379 checkComms(pvm_lvgroup(PECTLGROUP),"PEShutDown");
380 checkComms(pvm_exit(),"PEShutDown");
384 @heapChkCounter@ tracks the number of heap checks since the last probe.
385 Not currently used! We check for messages when a thread is resheduled.
388 int heapChkCounter = 0;
392 #endif /* PAR -- whole file */