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");
70 void NullException(STG_NO_ARGS)
72 fprintf(stderr,"Null_Exception: called");
74 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(op, dest, data1, data2)
93 unsigned data1, data2;
97 if (!ReplyTrace && op == REPLY_OK)
100 OpName = GetOpName(op);
101 /* fprintf(stderr, " %s [%x,%x] sent from %x to %x\n", OpName, data1, data2, mytid, dest);*/
106 @SendOp@ sends a 0-argument message with opcode {\em op} to
107 the global task {\em task}.
115 trace_SendOp(op, task,0,0);
117 pvm_initsend(PvmDataRaw);
118 pvm_send( task, op );
122 @SendOp1@ sends a 1-argument message with opcode {\em op}
123 to the global task {\em task}.
127 SendOp1(op, task, arg1)
132 trace_SendOp(op, task, arg1,0);
134 pvm_initsend(PvmDataRaw);
136 pvm_send( task, op );
141 @SendOp2@ is used by the FP code only.
145 SendOp2(op, task, arg1, arg2)
151 trace_SendOp(op, task, arg1, arg2);
153 pvm_initsend(PvmDataRaw);
156 pvm_send( task, op );
160 @SendOpV@ takes a variable number of arguments, as specified by {\em n}.
163 SendOpV( PP_STATS, StatsTask, 3, start_time, stop_time, sparkcount);
170 SendOpV(OPCODE op, GLOBAL_TASK_ID task, int n, ...)
173 SendOpV(op, task, n, va_alist)
190 trace_SendOp(op, task, 0, 0);
192 pvm_initsend(PvmDataRaw);
194 for (i = 0; i < n; ++i) {
195 arg = va_arg(ap, StgWord);
204 @SendOpNV@ takes a variable-size datablock, as specified by {\em
205 nelem} and a variable number of arguments, as specified by {\em
206 narg}. N.B. The datablock and the additional arguments are contiguous
207 and are copied over together. For example,
210 SendOpNV(PP_RESUME, tsoga.pe, 6, nelem, data,
211 (W_) ga.weight, (W_) ga.loc.gc.gtid, (W_) ga.loc.gc.slot,
212 (W_) tsoga.weight, (W_) tsoga.loc.gc.gtid, (W_) tsoga.loc.gc.slot);
215 Important: The variable arguments must all be StgWords.
221 SendOpNV(OPCODE op, GLOBAL_TASK_ID task, int nelem, StgWord *datablock, int narg, ...)
224 SendOpNV(op, task, nelem, datablock, narg, va_alist)
243 trace_SendOp(op, task, 0, 0);
244 /* fprintf(stderr,"SendOpNV: op = %x, task = %x, narg = %d, nelem = %d\n",op,task,narg,nelem); */
246 pvm_initsend(PvmDataRaw);
248 for (i = 0; i < narg; ++i) {
249 arg = va_arg(ap, StgWord);
250 /* fprintf(stderr,"SendOpNV: arg = %d\n",arg); */
253 arg = (StgWord) nelem;
256 /* for (i=0; i < nelem; ++i) fprintf(stderr, "%d ",datablock[i]); */
257 /* fprintf(stderr," in SendOpNV\n");*/
259 PutArgs(datablock, nelem);
267 @SendOpN@ take a variable size array argument, whose size is given by
268 {\em n}. For example,
271 SendOpN( PP_STATS, StatsTask, 3, stats_array);
277 SendOpN(op, task, n, args)
286 trace_SendOp(op, task, 0, 0);
288 pvm_initsend(PvmDataRaw);
296 @WaitForPEOp@ waits for a packet from global task {\em who} with the
297 opcode {\em op}. Other opcodes are handled by the standard exception handler.
300 PACKET WaitForPEOp(op, who)
307 GLOBAL_TASK_ID sender_id;
311 /* fprintf(stderr,"WaitForPEOp: op = %x, who = %x\n",op,who); */
312 while((p = pvm_recv(ANY_TASK,ANY_OPCODE)) < 0)
313 pvm_perror("WaitForPEOp: Waiting for PEOp");
315 pvm_bufinfo( p, &nbytes, &opcode, &sender_id );
317 match = (op == ANY_OPCODE || op == opcode) && (who == ANY_TASK || who == sender_id);
322 /* Handle the unexpected opcodes */
337 GLOBAL_TASK_ID sender_id;
338 pvm_bufinfo( p, &nbytes, &opcode, &sender_id );
348 GLOBAL_TASK_ID sender_id;
349 pvm_bufinfo( p, &nbytes, &opcode, &sender_id );
354 get_opcode_and_sender(p,popcode,psender_id)
357 GLOBAL_TASK_ID *psender_id;
360 pvm_bufinfo( p, &nbytes, popcode, psender_id );
365 @PEStartUp@ does the low-level comms specific startup stuff for a
366 PE. It initialises the comms system, joins the appropriate groups,
367 synchronises with the other PEs. Finally it receives from Control the
368 array of Global Task Ids.
379 fprintf(stderr, "Memory allocation of %u bytes failed\n", n);
391 long *buffer = (long *) xmalloc(sizeof(long) * nPEs);
392 GLOBAL_TASK_ID *PEs = (GLOBAL_TASK_ID *) xmalloc(sizeof(GLOBAL_TASK_ID) * nPEs);
394 mytid = _my_gtid; /* Initialise PVM and get task id into global
397 /* fprintf(stderr,"PEStartup, No. PEs = %d \n", nPEs); */
398 checkComms(pvm_joingroup(PEGROUP), "PEStartup");
399 /* fprintf(stderr,"PEStartup, Joined PEGROUP\n"); */
400 checkComms(pvm_joingroup(PECTLGROUP), "PEStartup");
401 /* fprintf(stderr,"PEStartup, Joined PECTLGROUP\n"); */
402 checkComms(pvm_barrier(PECTLGROUP, nPEs + 1), "PEStartup");
403 /* fprintf(stderr,"PEStartup, Passed PECTLGROUP barrier\n"); */
405 addr = WaitForPEOp(PP_PETIDS, ANY_GLOBAL_TASK);
406 GetArgs(buffer, nPEs);
407 for (i = 0; i < nPEs; ++i) {
408 PEs[i] = (GLOBAL_TASK_ID) buffer[i];
409 /* fprintf(stderr,"PEs[%d] = %x \n", i, PEs[i]); */
416 @PEShutdown@ does the low-level comms-specific shutdown stuff for a
417 single PE. It leaves the groups and then exits from pvm.
421 PEShutDown(STG_NO_ARGS)
423 checkComms(pvm_lvgroup(PEGROUP),"PEShutDown");
424 checkComms(pvm_lvgroup(PECTLGROUP),"PEShutDown");
425 checkComms(pvm_exit(),"PEShutDown");
429 @heapChkCounter@ tracks the number of heap checks since the last probe.
430 Not currently used! We check for messages when a thread is resheduled.
433 int heapChkCounter = 0;
437 #endif /* PAR -- whole file */