Copyright (c) 1993 Digital Equipment Corporation

This document describes each of the tools in the SRC Modula-3 distribution and how to use them. Briefly, the tools include a compiler, a linker, a pretty printer, and a line-based profiler. See also chapter~\ref{local} for tools and hints that are local to your installation.

Compiling

To compile a Modula-3 program, invoke m3(1). This driver is much in the style of cc(1); the output is an object file, a library or an executable program, according to the options.

m3 parses the command line and invokes the compiler and linker as required. m3 tells the compiler where to seek imported interfaces and where to find the Modula-3 runtime library. Arguments ending in .m3 or .i3 are assumed to name Modula-3 source files to be compiled. Arguments ending in .mo, .io or .o are assumed to name object files, possibly created by other language processors, that are to be linked with the object files created by m3. Arguments ending in .mc, .ic, or .c are assumed to name C source files to be compiled. Arguments ending in .ms, .is, or .s are assumed to name assembly language files to be translated into object files by the assembler. Arguments starting with - specify compiler options. Other arguments are assumed to name library files, and are simply passed along to the linker.

The source for a module named M is normally in a file named M.m3. The source for an interface named I must be in a file named I.i3. The main program is the module that implements the interface Main.

There are options to compile without linking, stop compiling after producing C, emit debugger symbols, generate profiling hooks, retain intermediate files, override search paths, select non-standard executables for the various passes, and pass arguments to individual passes. For the full details, see the m3(1) man page.

In a source file, an occurrence of IMPORT Mumble causes the compiler to seek an interface named Mumble. The compiler will step through a sequence of directories looking for the file Mumble.i3. It will parse the first such file that it finds, which is expected to contain an interface named Mumble. If no file Mumble.i3 exists, or if the parse fails, the compiler will generate an error. The particular sequence of directories to be searched is determined by the options passed to m3. See the m3(1) manual page for full details.

An example

Here's a simple program composed of a main module, an imported interface and its implementation.

In the file Main.m3:

       MODULE Main;
       IMPORT A;
       BEGIN
         A.DoIt ();
       END Main.
In the file A.i3:
       INTERFACE A;
       PROCEDURE DoIt ();
       END A.
In the file A.m3:
       MODULE A;
       IMPORT Wr, Stdio;

       PROCEDURE DoIt () =
          BEGIN
            Wr.PutText (Stdio.stdout, "Hello world.\n");
            Wr.Close (Stdio.stdout);
          END DoIt;

       BEGIN
       END A.
If SRC Modula-3 is installed correctly, the command
       m3 -make -why -o hello Main.m3 A.m3 A.i3
will compile the three compilation units and link them with the standard libraries. The result will be left in the executable file named hello.

m3makefiles

Once installed, SRC Modula-3 provides m3build(1), a replacement for plain make(1). The primary benefit provided by m3make is that the operational description found in most makefiles is replaced by a more declarative one. The result is that makefiles are smaller, simpler, and more portable. You're not required to use m3make, but we believe you will like it.

The m3makefile for the example above would be:

       implementation (Main)
       module (A)
       program (hello)

Language restrictions

With a few exceptions, SRC Modula-3 implements the Modula-3 language as defined in ``Systems Programming with Modula-3'' (\cite{m3-Nel91}). \subsection*{Arithmetic checking.} SRC Modula-3 does not generate any special checking for integer arithmetic overflow or underflow. You get whatever checking your C compiler gives you. We decided that the runtime checking was too expensive in a compiler that was constrained to produce C. Depending on your machine, the {\tt FloatMode} interface may be used to control floating point exceptions. \subsection*{Packed types.} \index{packed fields} Packed types are restricted. BITS n FOR T is treated as T everywhere except when applied to a field in a record. In that case, the field is implemented by a {\em bitfield} of width n in a C struct. Otherwise, a \modula field is implemented as a {\em member} of a C struct. Consequently, \modula types that would require the C field to span word boundaries are not accepted by SRC Modula-3. \subsection*{Stack overflow checking.} \index{overflow!stacks} \index{thread!stacks} SRC Modula-3 does not reliably detect thread stack overflows. Stacks are only checked for overflow on procedure entry. No checking is done on external procedures. Thread stacks are allocated in fixed size chunks. The required Thread interface has been augmented with the SizedClosure type to allow arbitrary sized stacks. The default size can be adjusted with Thread.MinDefaultStackSize and Thread.IncDefaultStackSize. \subsection*{Exception semantics.} \index{exceptions} \index{exceptions!setjmp, longjmp@{\tt setjmp}, {\tt longjmp}} \index{setjmp@{\tt setjmp}} \index{longjmp@{\tt longjmp}} SRC Modula-3 uses C's {\tt setjmp}/{\tt longjmp} mechanism to unwind the stack when raising an exception. A problem can occur: assignments may appear to be undone. For example, consider
      TRY
        i := 3;
        P ();
      EXCEPT E:
        j := i;
      END;
where {\tt P} raises exception {\tt E}. The compiler generates a {\tt setjmp} at the beginning of the try statement. If the C compiler allocates variable {\tt i} to a register, the assignment of {\tt 3} may be lost during the {\tt longjmp} and branch that gets to the handler. \subsection*{Method constants.} The language definition says that if {\tt T} is an object type and {\tt m} one of its methods, {\tt T.m} denotes the procedure value that implements that method and that this value is a constant. In SRC Modula-3, {\tt T.m} denotes the correct procedure constant, but since the compiler generates runtime code to locate the method, some uses of the constant that the {\tt C} compiler must resolve at link time will cause {\tt C} errors. For example,
      CONST P = T.m;  BEGIN P (...) ...
will work, since no initialized {\tt C} storage is allocated for {\tt P}. But the following generates initialized storage and will fail
      CONST X = ARRAY [0..2] OF Proc { T.m, ..};
Similarly, although Modula-3 allows it, the following cannot be evaluated at compile time
      CONST X = (T.m = MyProcedure);
\section{Pragmas} %================ \index{pragmas} SRC Modula-3 recognizes the pragmas described below. \subsection*{\tt <*EXTERNAL*>} \index{external linkage} \index{C linkage@{\tt C} linkage} \index{<*EXTERNAL*>@{\tt <*EXTERNAL*>}} The pragma <*EXTERNAL N:L*> may precede an interface or a procedure or variable declaration in an interface. It asserts that the following entity is named ``N'' and implemented in language ``L''. If ``N'' is omitted, the external name is the \modula name. The default and only recognized value for ``L'' is C. The ``:'' is only required when specifying ``L''. ``N'' and ``L'' may be \modula identifiers or string literals. The names of external procedures and variables are passed through to the C compiler unchanged. {\em The types of external variables, the types of formal parameters, the types of results, and the raises clauses of external procedures are all assumed to be correct and are not checked against their external implementation.} Standard calling conventions are used when calling external procedures. Beginning an interface with <*EXTERNAL*> declares all of the procedures and variables in that interface external. For example:
      <*EXTERNAL*> INTERFACE OS;
      VAR errno: INTEGER;
      PROCEDURE exit (i: INTEGER);
      END OS.
allows importers of OS to access the standard \unix symbols errno and exit through the names OS.errno and OS.exit respectively. Alternatively, the following interface provides access to the same two symbols, but uses a more conventional \modula name for the procedure:
      INTERFACE OS;
      <*EXTERNAL errno:C *> VAR errno: INTEGER;
      <*EXTERNAL exit:C  *> PROCEDURE Exit (i: INTEGER);
      END OS.
If several variables are declared within a single <*EXTERNAL*> VAR declaration, they are all assumed to be external. The external pragma may optionally specify a name different from the \modula name. For example:
      INTERFACE Xt;
        <*EXTERNAL "_XtCheckSubclassFlag" *>
        PROCEDURE CheckSubclassFlag (...);
        ...
defines a procedure named Xt.CheckSubclassFlag in \modula and named _XtCheckSubclassFlag in the generated C. \subsection*{\tt <*INLINE*>} \index{<*INLINE*>@{\tt <*INLINE*>}} The pragma <*INLINE*> may precede a procedure declaration. The pragma is allowed in interfaces and modules. SRC Modula-3 recognizes but ignores this pragma. For example:
      INTERFACE X;
      <*INLINE*> PROCEDURE P (i: INTEGER);
      <*INLINE*> PROCEDURE Q ();
      END X.
declares X.P and X.Q to be inlined procedures. \subsection*{\tt <*ASSERT*>} \index{<*ASSERT*>@{\tt <*ASSERT*>}} \index{assertions} \index{correctness} The pragma <*ASSERT expr*> may appear anywhere a statement may appear. It is a static error if ``expr'' is not of type BOOLEAN. At runtime ``expr'' is evaluated. It is a checked runtime error if the result is FALSE. Assertion checking can be disabled with the -a compiler switch. \subsection*{\tt <*TRACE*>} \index{<*TRACE*>@{\tt <*TRACE*>}} The pragma <*TRACE expr*> may appear at the end of any variable or formal declaration. This pragma will generate tracing calls whenever the declared variable is modified. The ``expr'' must evaluate to a procedure of two arguments. The first argument is the name of the traced variable, a TEXT. The second argument is the traced variable. Note that any of the formal passing modes may be used with the second argument. For example:
       MODULE M;
       VAR x: Foo <*TRACE MyTrace.FooChanged*>;
will cause
       MyTrace.FooChanged ("M.x", x)
to be generated after each statement that modifies x. Variable aliasing is not tracked, so
       WITH  alias = x DO  INC(alias) END
will not generate any tracing. The pieces of Modula-3 grammar affected by <*TRACE expr*> are:
    VariableDecl = IdList (":" Type & ":=" Expr) V_TRACE.
    Formal       = [Mode] IdList (":" Type & ":=" ConstExpr) V_TRACE.
    ForSt        = FOR Id V_TRACE ":=" Expr TO Expr [BY Expr] DO S END.
    Handler      = QualId {"," QualId} ["(" Id V_TRACE ")"] "=>" S.
    TCase        = Type {"," Type} ["(" Id V_TRACE ")"] "=>" S.
    Binding      = Id V_TRACE "=" Expr.
    V_TRACE      = [ "<*" TRACE  Expr "*>" ].
The pragma <*TRACE stmt-list*> may appear immediately after any BEGIN. The specified ``stmt-list'' will be inserted after each statement of the block started by the BEGIN. For example:
       BEGIN <* TRACE  INC(cnt); MyTrace(cnt) *>
         i := j;
         j := i;
       END;
will generate INC(cnt); MyTrace(cnt) after each of the assignment statements. \subsection*{\tt <*FATAL*>} \index{<*FATAL*>@{\tt <*FATAL*>}} \index{exceptions!lint} The pragma <*FATAL id-list*> may appear anywhere a declaration may appear. It asserts that the exceptions named in ``id-list'' may be raised, but unhandled in the containing scope. If they are, it's fatal and the program should crash. Effectively, the <*FATAL*> pragma disables a specific set of ``potentially unhandled exception'' warnings. If ``id-list'' is ANY, the pragma applies to all exceptions. The effects of the <*FATAL*> pragma are limited to its containing scope --- they cannot be imported from interfaces. For example:
      EXCEPTION InternalError;
      <*FATAL InternalError*>
at the top-level of a module M means that no warnings will be generated for procedures in M that raise but don't list InternalError in their RAISES clauses. Similarly,
      PROCEDURE X() RAISES {} =
      BEGIN
        ...
        <*FATAL ANY*> BEGIN
           List.Walk (list, proc);
        END;
        ...
      END X;
specifies that although X raises no exceptions and List.Walk may, no warnings should be generated. \subsection*{\tt <*UNUSED*>} \index{<*UNUSED*>@{\tt <*UNUSED*>}} \index{unused symbols} The pragma <*UNUSED*> may precede any declaration. It asserts that the entity in the following declaration is not used and no warnings should be generated. For example, the procedures that implement the default methods for an object may not need all of the actual parameters:
      PROCEDURE DefaultClose (<*UNUSED*> wr: Wr.T) =
         BEGIN (* do nothing *) END DefaultClose;
\subsection*{\tt <*OBSOLETE*>} \index{obsolete symbols} \index{<*OBSOLETE*>@{\tt <*OBSOLETE*>}} The pragma <*OBSOLETE*> may precede any declaration (e.g. <*OBSOLETE*> PROCEDURE P ();). A warning is emitted in any module that references an obsolete symbol. This feature is used to warn clients of an evolving interface that they are using features that will disappear in the future. \subsection*{\tt <*NOWARN*>} \index{<*NOWARN*>@{\tt <*NOWARN*>}} \index{warnings} \index{compiler!warnings} The pragma <*NOWARN*> may appear anywhere. It prevents warning messages from being issued for the line containing the pragma. It is probably better to use this pragma in a few places and enable all warnings with the -w1 switch than to ignore all warnings. \subsection*{\tt <*LINE*>} \index{line numbers} \index{<*LINE*>@{\tt <*LINE*>}} For the benefit of preprocessors that generate \modula programs, the compiler recognizes a <*LINE ... *> pragma, in two forms:
      <*LINE number filename *>
      <*LINE number *>
where \verb+number+ is an integer literal and \verb+filename+ is a text literal. This pragma causes the compiler to believe, for purposes of error messages and debugging, that the line number of the following source line is \verb+number+ and that the current input file is \verb+filename+. If \verb+filename+ is omitted, it is assumed to be unchanged. <*LINE ... *> may appear between any two Modula-3 tokens; it applies to the source line following the line on which it appears. Here's an example: \verb+<*LINE 32 "SourceLoc.nw" *>+. \subsection*{\tt <*PRAGMA*>} \index{<*PRAGMA*>@{\tt <*PRAGMA*>}} The pragma <*PRAGMA id-list*> may appear anywhere. It notifies the compiler that pragmas beginning with the identifiers in ``id-list'' may occur in this compilation unit. Since the compiler is free to ignore any pragma, the real effect of <*PRAGMA*> is to tell the compiler that pragmas it doesn't implement are coming, but they shouldn't cause ``unrecognized pragma'' warnings. \section{Linking} %================ \index{linking} SRC Modula-3 requires a special two-phase linker. You must link \modula programs with m3. The first phase of the linker checks that all version stamps are consistent, generates flat struct* declarations for all opaque and object types, and builds the initialization code from the collection of objects to be linked. The second phases calls {\tt ld} to actually link the program. \index{files!suffixes} \index{files!.ix, .mx, .ax@{\tt .ix}, {\tt .mx}, {\tt .ax}} \index{.ix, .mx, .ax files@{\tt .ix}, {\tt .mx}, {\tt .ax} files} The information needed by the first phase is generated by the compiler in files ending in .ix and .mx. Libraries containing \modula code must be created using m3 -a. m3 will combine the .ix and .mx files for the objects in the library into a new file ending in .ax. The .ix, .mx, and .ax files must reside in the same directory as their corresponding .io, .mo and .a files. If m3 encounters a library without a .ax file, it assumes that the library contains no \modula code. \index{version stamps} \index{safe linkage} For every symbol X.Z exported or imported by a module, the compiler generates a version stamp. These stamps are used to ensure that all modules linked into a single program agree on the type of X.Z. The linker will refuse to link programs with inconsistent version stamps. \section{Runtime arguments} %========================== \index{runtime arguments} \index{M3 arguments@{\tt "@M3} arguments} \index{showheap@{\tt "@M3showheap}} \index{M3showheap@{\tt "@M3showheap}} \index{showthread@{\tt "@M3showthread}} \index{M3showthread@{\tt "@M3showthread}} \index{nogc@{\tt "@M3nogc}} \index{M3nogc@{\tt "@M3nogc}} \index{noincremental@{\tt "@M3noincremental}} \index{M3noincremental@{\tt "@M3noincremental}} \index{nogenerational@{\tt "@M3generational}} \index{M3nogenerational@{\tt "@M3generational}} \index{novm@{\tt "@M3novm}} \index{M3novm@{\tt "@M3novm}} \index{nogc@{\tt "@M3nogc}} \index{M3nogc@{\tt "@M3nogc}} \index{paranoidgc@{\tt "@M3paranoidgc}} \index{M3paranoidgc@{\tt "@M3paranoidgc}} Command line arguments given to Modula-3 programs are divided in two groups. Those that start with the characters @M3 are reserved for the \modula runtime and are accessible via the RTParams interface (we call those the {\em runtime parameters}). The others are accessible via the Params, ParseParams, and RTArgs interfaces (these are the {\em program arguments}). The following runtime parameters are recognized today; others are simply ignored. \begin{itemize} \item @M3nogc turns the garbage collector off. \item @M3showheap={\it name} activates the logging of heap allocation and garbage collection events. The program forks a process running the {\it name} program, and sends it these events as they occur. If ={\it name} is ommitted, the {\tt showheap} program is forked (it is part of the {\tt tools} archive); this program displays the status of the heap pages. See its man page for more details. \item @M3showthread={\it name} activates the logging of thread switching events. The program forks a process running the {\it name} program, and sends it these events as they occur. If ={\it name} is ommitted, the {\tt showthread} program is forked (it is part of the {\tt tools} archive); this program displays the status of the various threads. See its man page for more details. \item @M3noincremental disables incremental garbage collection; uses stop-and-copy instead. \item @M3nogenerational disables generational garbage collection. \item @M3novm disables the use of VM protection by the garbage collector. Implies @M3noincremental and @M3nogenerational. \item @M3paranoidgc checks the heap for sanity after each collection. \end{itemize} \section{Garbage Collection} %=========================== \index{garbage collection} \index{garbage collection!copying} \index{collector, copying} \index{hashing REFs@hashing {\tt REF}s} A crucial fact for clients of the garbage collector to know is that {\em objects in the heap move}. If all references to a traced heap object are from other traced heap objects, the collector may move the referent. Hence, it is a bad idea to hash pointer values. References from the stack or untraced heap into the traced heap are never modified. The new collector is, by default, incremental and generational. The interruptions of service should be very small, and the overall performance should be better than with the previous collectors. The use of VM protection is currently implemented only for the DS3100 architecture. On other architectures, @M3novm is the default. Note that the new optional background collection thread is not on by default; this may change in the future. The procedures RTHeap.DisableCollection and RTHeap.EnableCollection are now marked as obsolete, although they still work; preferred new alternatives are described in the \intf{RTHeap} interface. \index{debugging} \index{gdb@{\tt gdb}} \index{bus error} \index{VM faults} When you debug a Modula-3 program, you might find it simplest to run it with the @M3novm switch. For example, if you use gdb, you can start your program with
    (gdb) run MyProgram @M3novm
If you do not use the @M3novm flag, you must set gdb to ignore VM faults generated on the collector's behalf, by typing
    (gdb) handle 11 noprint pass
And then, without @M3novm, you might not be able to examine the heap when the program stops, because the heap may be protected. You can turn off all current heap protection by telling gdb
    (gdb) call RTHeap__FinishVM()
If you also want the collector not to use VM protection in the future (i.e., if you wish you'd typed @M3novm to start with), you can type
    (gdb) call RTHeap__NoVM()
If your program is not run from the debugger, and it dumps core, the runtime automatically calls the equivalent of a RTHeap.FinishVM() to let you examine the heap in the core file. \index{sigvec@{\tt sigvec}} \index{fork@{\tt fork}} \index{vfork@{\tt vfork}} Because of the use of VM protection by the collector, there are some additional constraints on what programs may legally do. For example, you cannot pass an address on the heap as an argument to sigvec(2). These restrictions are documented in \intf{RTHeapDepC.c}. If they seem onerous, we might be able to eliminate some. Note also that fork() and vfork() are now relatively expensive operations, since they cause the current collection to finish; this situation may improve in a future release. \section{Debugging} %================== \index{debugging} \index{dbx@{\tt dbx}} \index{gdb@{\tt gdb}} Since an intermediate step of the \modula compiler is to produce C code, you may use any debugger for which your C compiler can produce debugging information; in most cases, this means {\tt dbx} or {\tt gdb}. However, this mechanism has limitations: the C compiler generates source-level information that relates the executable program to the intermediate C code, not to the \modula source code. We attempted to reflect as much as possible of the source-level \modula information into the intermediate C code. But there are still some shortcomings that you should know about. \subsection*{Names} %----------------- \index{name mangling} \index{debugging!names} \index{names, in the debugger} Global names (i.e. top-level procedures, constants, types, variables, and exceptions) are prefixed by their module's name and two underscores. For example, in an interface or module named X, the C name of a top-level procedure P would be X__P. Note, there are two underscores between X and P. Local names (e.g. of local variables and formal parameters) are preserved. The compiler will issue a warning and append an underscore to any \modula name that is a C reserved word. \subsection*{Types} %----------------- \index{type names} \index{t1fc3a882@{\tt \_t1fc3a882}} \modula is based on structural type equivalence, C is not. For this reason, the compiler maps all structurally equivalent \modula types into a single C type. These C types have meaningless names like _t1fc3a882. The \modula type names are equated to their corresponding C type. Unfortunately variables are declared with the C type names. So, if you ask your debugger ``what is the type of v?'', it will most likely answer, ``_t13e82b97''. But, if you ask ``what is _t13e82b97?'' it will most likely give you a useful type description. The table~\ref{table:conversion} indicates the C types corresponding to \modula types. \begin{table} \begin{center} \begin{tabular}{p{1.3in}p{4.6in}} \multicolumn{1}{c}{\modula} & \multicolumn{1}{c}{C}\\ \hline enumeration & unsigned char, unsigned short or unsigned int depending on the number of elements in the enumeration. \\ \\ INTEGER & int \\ \\ subrange & char, short or int, possibly unsigned, depending on the base type of the subrange. Subranges of enumerations are implemented by the same type as the full enumeration. Subranges of INTEGER are implemented by the smallest type containing the range. For example, the type [0..255] is mapped to unsigned char and [-1000..1000] is mapped to short. \\ \\ REAL & float \\ \\ LONGREAL & double \\ \\ EXTENDED & double \\ \\ $ARRAY I OF T$ & struct { tT elts[n] }, where tT is the C type of T and n is NUMBER(I). \\ \\ $ARRAY^n OF T$ & $struct { tT* elts; int size[n ] }$, where tT is the C type of T and elts is a pointer to the first element of the array. \\ \\ RECORD ... END & struct{ ... } with the same collection of fields as the original record. \\ \\ BITS n FOR T & Usually tT where tT is the the C type of T. When T is an ordinal type and the packed type occurs within a record, it generates a C bit field. \\ \\ SET OF T & struct { int elts[n] } where n is $\lceilNUMBER (T) / sizeof(int)\rceil$. \\ \\ \begin{tabular}[t]{@{}l@{}} REF T \\ UNTRACED REF T \\ \end{tabular} & tT* where tT is the C type of T. \\ \\ OBJECT ... END & ADDRESS, a {\tt typedef} for char* or void* (depending on the system) defined in M3Machine.h. Each use of an object reference is cast into a pointer of the appropriate type at the point of use. \\ \\ PROCEDURE (): T & Usually tT *(proc)() where tT is the C type of T. If T is a record or array, an extra VAR parameter is passed to the procedure which it uses to store the return result. %% \\ \\ \end{tabular} \end{center} \caption{Type implementations} \label{table:conversion} \end{table} \index{debugging!printing REFs@printing {\tt REF}s} \index{REF!printing} \index{type names} Despite the fact that the compiler turns all object references into char*, the linker generates useful type declarations. These declarations are available under the type's global name. For example, to print an object o of type Wr.T, type print *(Wr__T)o. Note that if o was really a subtype of Wr.T, say TextWr.T, then you must use print *(TextWr__T)o to see the additional fields. If the same type appears with two names in a program, the linker arbitrarily picks one. \index{debugging!printing TEXTs@printing {\tt TEXT}s} \index{TEXT!printing} To print the null terminated string in a variable of type TEXT (or Text.T) named txt, type print *(char**)txt. \index{debugging!printing REFs@printing {\tt REF}s} \index{REF!printing} \index{typecodes} \index{typecells} \index{type names} \index{runtime!type headers} If you don't know the type of a traced reference, you may be able to use the runtime information to discover it. Given a reference r, print *(_refHeader*)(((char*)r)-4) will print its typecode x, and print *_types[x] will print the corresponding typecell. A typecell includes a type's \modula name as a C string (typecell.name). If the type doesn't have a \modula name, its internal is the concatenation of ``_t'' and typecell.selfID in hex. \subsection*{File names and line numbers} %--------------------------------------- Due to liberal use of the #line mechanism of C, the \modula file names and line numbers are preserved. Your debugger should give you the right names and line numbers and display the correct \modula source code (if it includes facilities to display source code). Note that uses of the <*LINE*> pragma are propagated into the intermediate C code. \subsection*{Debugger quirks} \index{.dbxinit file@{\tt .dbxinit} file} \index{dbxinit file@{\tt .dbxinit} file} \index{SIGVTALRM@{\tt SIGVTALRM}} \index{Unix!signals} Most debuggers have a few quirks. dbx is no exception. We've found that having a .dbxinit file in your home directory with the following contents prevents many surprises:
    ignore SIGVTALRM
    set $casesense = 1
The first line tells dbx to ignore virtual timer signals. They are used by the \modula runtime to trigger thread preemptions. The second line tells dbx that your input is case sensitive. \subsection*{Procedures} %---------------------- \modula procedures are mapped as closely as possible into C procedures. Two differences exist: ``large'' results and nested procedures. \index{structured function results} \index{procedures!structured results} \index{functions!see{procedures}} First, procedures that return structured values (i.e. records, arrays or sets) take an extra parameter. The last parameter is a pointer to the memory that will receive the returned result. This parameter was necessary because some C compilers return structured results by momentarily copying them into global memory. The global memory scheme works fine until it's preempted by the \modula thread scheduler. \index{procedures!nested} \index{nested procedures} \index{environments, procedure} \index{closures} Second, nested procedures are passed an extra parameter. The first parameter to a nested procedure is a pointer to the local variables of the enclosing block. To call a nested procedure from the debugger, pass the address of the enclosing procedure's local variable named frame. When a nested procedure is passed as a parameter, the address of the corresponding C procedure and its extra parameter are packaged into a small closure record. The address of this record is actually passed. Any call through a formal procedure parameter first checks to see whether the parameter is a closure or not and then makes the appropriate call. Likewise, assignments of formal procedure parameters to variables perform runtime checks for closures. <*EXTERNAL*> procedures have no extra parameters. {\em except if they return large results??} \subsection*{Threads} %------------------- \index{debugging!threads} There is no support for debugging threads. That is, there is no mechanism to force the debugger to examine a thread other than the one currently executing. Usually you can get into another thread by setting a breakpoint that it will hit. There is no mechanism to run a single thread while keeping all others stopped. If your debugger allows you to call procedures in a stopped program, as both dbx and gdb do, then print Thread__DumpEverybody() will produce a table listing the status of all threads. \section{Thread scheduling} %========================== \index{scheduling} \index{threads!scheduling} \index{threads!user level} This version of SRC Modula-3 has a more flexible scheduling algorithm than the previous versions. Here is a rough explanation of its behaviour. All threads are kept in a circular list. This list is modified only when new threads are created or when threads exit; that is, the relative order of threads in this list is never modified. When the scheduler comes into action, the list of threads is scanned starting with the thread following the one currently running, until a thread that can execute is found: \begin{itemize} \item if it was preempted by the scheduler, it can execute \item if it is waiting for a condition or a mutex that is still held, it cannot execute \item if it has blocked because of a call to {\tt Time.Pause} (or a similar procedure), it can execute iff the timeout is now expired \item if it has blocked because of a call to {\tt RTScheduler.IOSelect} (or a similar procedure), it can execute iff the timeout is now expired or a polling {\tt select(2)} returns a non-zero value. \end{itemize} If such a thread is found, it becomes active. \index{Time.Pause@{\tt Time.Pause}} \index{RTScheduler.IOSelect@{\tt RTScheduler.IOSelect}} \index{select@{\tt select}} \index{blocking, process} \index{waiting, process} If no thread can execute, and there are no threads blocked in a {\tt Time.Pause} or a {\tt RTScheduler.IOSelect}, a deadlock situation is detected and reported. Otherwise, a combination of the file descriptors sets (OR of all the file descriptors sets) and timeouts (MIN of all the timeouts) is formed, {\tt select(2)} is called with those arguments and the whole process of searching for an executable thread is redone. This ensure that the Unix process does not consume CPU resources while waiting. The scheduler is activated when the running thread tries to acquire a mutex which is locked, waits for a condition, calls {\tt Time.Pause} (or a similar procedure) with a future time, calls {\tt RTScheduler.IOSelect} (or a similar procedure) with a non-zero valued timeout and no files are ready at the time of the call, or the time allocated to the thread has expired (preemption). \index{threads!preemption} \index{preemption} Preemption is implemented using the Unix virtual interval timer. {\tt RTScheduler.SetSwitchingInterval} can be used to change the interval between preemptions. SRC Modula-3 no longer uses the real time interval timer nor the profiling interval timer for thread scheduling; these are available to the program. \index{sigpause@{\tt sigpause}} \index{select@{\tt select}} Because of the preemption implementation, Unix kernel calls will block the process (i.e. the Unix process sleeps even though some threads could run). However, {\tt Time.Pause} and {\tt RTScheduler.IOSelect} provide functional equivalents of {\tt sigpause(2)} and {\tt select(2)} that do not cause the process to block. \section{Profiling} %================== \index{profiling} \index{prof@{\tt prof}} \index{gprof@{\tt gprof}} \index{pixie@{\tt pixie}} In addition to the usual profiling tools (e.g. see prof(1), gprof(1) and pixie(1)), SRC Modula-3 provides support for line-based profiling. \index{analyze coverage@{\tt analyze\_coverage}} \index{coverage} \index{profiling!line-based} \index{-Z@{\tt -Z}} To enable collection of data during the execution of programs, give the -Z option to the m3 command for the compilation of the modules you want to examine and also for the linking of the program. To interpret the result, run analyze_coverage(1). Note that because of the extensive data collection performed by this mode of profiling, the execution time of the program can be significantly larger when it is enabled; thus, simultaneous time profiling can produce erroneous results. For the same reason, the profiling data file is rather large; furthermore, as it is augmented by each execution of the program, you may want to compress it from time to time (see analyze_coverage(1) for more details). \section{Pretty printing} %======================== \index{m3pp@{\tt m3pp}} SRC Modula-3 includes a pretty-printer for \modula programs. It is accessible as m3pp(1). Read its man page to find out how to use it. \section{Gnuemacs support} %========================= \index{.emacs@{\tt .emacs}} \index{editting} \index{gnuemacs@{\tt gnuemacs}} \index{gnuemacs!Modula-3 mode} \index{epoch@{\tt epoch}} \index{emacs@{\tt emacs}} \subsection{\tt modula-3-mode} %----------------------------- \index{gnuemacs!Modula-3 mode} \index{command completion} SRC Modula-3 comes with a mode for editing Modula-3 programs under {\tt gnuemacs}. Here is a list of the key things this mode provides: \begin{itemize} \item Indenting/pretty-printing \index{pretty-printing} Modula-3 mode gives you access to two methods of formatting code, one ``batch'' and one ``interactive.'' The batch method invokes the program m3pp, which takes a program unit such as a procedure and formats it completely. The gnuemacs commands that invoke m3pp are M-x m3::pp-buffer which pretty prints the current buffer, M-x m3::pp-region which pretty-prints the code between mark and point, and M-x m3::pp-unit which pretty-prints the ``unit'' containing the cursor. (A unit is a top-level construct such as CONST, TYPE, VAR, or PROCEDURE.) m3::pp-buffer, m3::pp-region and m3::pp-unit are bound to the keys C-c b, C-c r and C-c u, respectively. The other method of formatting text is a more traditional one for gnuemacs, in which there the language mode provides a key that indents the current line appropriately. In keeping with the convention used in modes for other languages such as Lisp and C, the key used is TAB. Typing TAB on a line indents the current line in a way that is (we hope) appropriate given the lines that precede it. The two formatting methods are not mutually exclusive; perhaps you like the way m3pp lines up columns in declarations, but you also like to keep things indented while you type. You can use the electric mode to get things close, then invoke m3pp when you're done. \item Avoidance of typing: \index{electric Modula-3 mode} Modula-3 mode offers some aid if you don't like typing a lot of uppercase keywords. The TAB actually serves double duty; it not only indents the current line, but when invoked at the end of a word, it attempts to complete the current word as a keyword. For example b TAB expands the b to BEGIN, provided the b appears in a context where BEGIN may be a valid keyword. There are some fairly extensive rules governing the contexts in which a given keyword is a valid completion; the net result is that it is seldom necessary to type more than one letter to get the correct completion. If you specify a non-unique prefix of a set of keywords, it chooses the first in an ordering intended to capture frequency of use; it also presents the other choices, and typing TAB repeatedly cycles through these choices. A pair of related features are ``END-completion'' and ``END-matching.'' If the elisp variable m3::electric-end is set to 'all, completing the keyword END has the additional effect of finding the construct that the END completes. If that construct is a an interface, module, or procedure, it fills in the name of the completed construct after the END; otherwise, it inserts a comment containing the keyword of the completed construct. If m3::electric-end is 'proc-mod, it only fills in real names, never keyword comments. Independently, a non-nil value of the elisp variable m3::blink-end-matchers causes completion of END to blink the cursor briefly at the beginning of the completed construct. \item Finding files. \index{mpindex} \index{interfaces, finding} \index{browsing interfaces} The key C-c i is bound to m3::show-interface, which expects the point to be in an interface name, and attempts to find that interface and display it in another window. (If you are using epoch and the value of m3::show-file-new-screen is t, which is the default, the interface will be displayed in a new epoch screen, that is, a top-level X window. If you use m3-path files, m3::show-interface will use those to provide a search path; otherwise, it uses a built-in list of directories. The default value of this list is the one used at SRC; other sites will probably need to modify this. The key C-c m is bound to m3::show-implementation. This attempts to find the module that implements the interface in the current buffer. This function relies on a SRC-specific convention where public interfaces are symbolic links to home directories for the packages that export them, which also contain the implementations. Obviously, this site-specific convention may not work outside of SRC, and m3::show-implementation may need to be re-implemented or abandoned. \end{itemize} To have the Modula-3 mode automatically invoked when visiting a Modula-3 source file, you should put in your .emacs:
    (autoload 'modula-3-mode "modula3")
    (setq auto-mode-alist 
         (append '(("\\.ig$" . modula-3-mode)
                   ("\\.mg$" . modula-3-mode)
                   ("\\.i3$" . modula-3-mode)
                   ("\\.m3$" . modula-3-mode))
                   auto-mode-alist))	
It is also convenient to have the lines:
    (setq completion-ignored-extensions
       (append '(".mo" ".mx" ".mc" ".io" ".ix") completion-ignored-extensions))
so that you don't get the files with those extensions offered as possible completions. Your system administrator may have inserted these lines in the default macro files for your system. \subsection{Tags} %---------------- \index{gnuemacs!tags} \index{m3tags@{\tt m3tags}} \index{tags} There is also a program to build tags file for \modula programs: m3tags; see the manpage for the details. When the system is installed, a tag file for the public interfaces is built. To access it, you need in your .emacs (or in the system initialization file) the line:
        (visit-tags-table "LIB_USE/FTAGS")
where LIB_USE is the place where the \modula libraries have been installed. \section{Unix signals} %===================== \index{Unix!signals} \index{signals, Unix} On Unix the Modula-3 runtime catches three signals: SIGSEGV, SIGBUS, and SIGVTALRM. Otherwise, the runtime leaves the default Unix signal handlers unaltered. \index{SIGSEGV@{\tt SIGSEGV}} \index{segmentation violation} SIGSEGV indicates a ``segmentation violation'' and is often signaled when a process dereferences NIL. The runtime catches SIGSEGV, prints an error message, and attempts to crash with a ``core file''. \index{bus error} \index{SIGBUS@{\tt SIGBUS}} SIGBUS indicates a ``bus error'' (pdp-11 days?) and is often signaled when the process accesses unmapped memory (usually a thread stack overflow). The runtime catches SIGSEGV, prints an error message, and attempts to crash with a ``core file''. \index{SIGVTALRM@{\tt SIGVTALRM}} \index{threads!preemption} \index{timers} SIGVTALRM is the ``virtual timer alarm''. It is used to periodically preempt the running thread. \section{Keeping in touch} %========================= \index{comp.lang.modula3@\newsgroup} \index{Usenet} \index{news group} \index{m3-request@{\tt m3-request"@src.dec.com}} \paragraph{\newsgroup\relax} is a Usenet newsgroup devoted to \modula. There you will find discussions on the language and how to use it, annoucements of releases (both of SRC Modula-3 and of other systems). Since not everybody has access to Usenet, we also maintain a relay mailing list, to which we resend the articles appearing in \newsgroup. To be added to this list, send a message to m3-request@src.dec.com. You may post articles to \newsgroup by sending them to m3@src.dec.com. \index{bug reports} \paragraph{Reporting bugs.} We prefer that you send bug reports to m3-request@src.dec.com. After we have reviewed your report, we may post an article in \newsgroup, describing the bug and a workaround or a fix. Needless to say, this implementation probably has many bugs. We are quite happy to receive bug reports. We can't promise to fix them, but we will try. When reporting a bug, please send us a short program that demonstrates the problem.