a fix in the previous commit
[charm.git] / doc / tcharm / manual.tex
1 \documentclass[10pt]{article}
2 \usepackage{../pplmanual}
3 \input{../pplmanual}
4
5 \newcommand{\tcharm}{\textsc{TCharm}}
6
7 \makeindex
8
9 \title{Threaded \charmpp Manual}
10 \version{1.0}
11 \credits{
12 The initial version of Threaded \charmpp{} was developed
13 in late 2001 by Orion Lawlor.
14 }
15
16 \begin{document}
17
18 \maketitle
19
20 \section{Motivation}
21
22 \charmpp{} includes several application frameworks, such as the 
23 Finite Element Framework, the Multiblock Framework, and AMPI.  
24 These frameworks do almost all their work in load balanced, 
25 migratable threads.  
26
27 The Threaded \charmpp{} Framework, \tcharm{}, provides both
28 common runtime support for these threads and facilities for
29 combining multiple frameworks within a single program.
30 For example, you can use \tcharm{} to create a Finite Element
31 Framework application that also uses AMPI to communicate between
32 Finite Element chunks.
33
34 Specifically, \tcharm{} provides language-neutral interfaces for:
35 \begin{enumerate}
36 \item{Program startup, including read-only global data setup and the
37 configuration of multiple frameworks.}
38 \item{Run-time load balancing, including migration.}
39 \item{Program shutdown.}
40 \end{enumerate}
41
42 The first portion of this manual describes the general properties 
43 of \tcharm{} common to all the application frameworks, such as 
44 program contexts and how to write migratable code.
45 The second portion describes in detail how to combine separate 
46 frameworks into a single application.
47
48
49 \section{Basic \tcharm{} Programming}
50 Any routine in a \tcharm{} program runs in one of two contexts:
51
52 \begin{description}
53
54 \item[Serial Context] Routines that run on only one processor
55 and with only one set of data. There are absolutely
56 no limitations on what a serial context routine can do---it 
57 is as if the code were running in an ordinary serial program.
58 Startup and shutdown routines usually run in the serial context.
59
60 \item[Parallel Context] Routines that run on several processors,
61 and may run with several different sets of data on a single processor.
62 This kind of routine must obey certain restrictions.  The program's
63 main computation routines always run in the parallel context.
64
65 \end{description}
66
67 Parallel context routines run in a migratable, 
68 user-level thread maintained by \tcharm{}.  
69 Since there are normally several of these threads per processor,
70 any code that runs in the parallel context has to be thread-safe.
71 However, \tcharm{} 
72 is non-preemptive, so it will only switch threads when you make
73 a blocking call, like ``MPI\_Recv" or ``FEM\_Update\_field".
74
75
76
77 \subsection{Global Variables}
78 \label{sec:global}
79 By ``global variables'', we mean anything that is stored at a fixed, 
80 preallocated location in memory.  In C, this means variables declared 
81 at file scope or with the \kw{static} keyword.  In Fortran, this is
82 % variables that are part of a \kw{COMMON} block or declared inside 
83 % a \kw{MODULE}.
84 either variables that are part of a \kw{COMMON} block, declared inside 
85 a \kw{MODULE} or variables with the \kw{SAVE} attribute.
86
87 Global variables are shared by all the threads on a processor, which
88 makes using global variables extremely error prone.
89 To see why this is a problem, consider a program fragment like:
90
91 \begin{alltt}
92   foo=a
93   call MPI_Recv(...)
94   b=foo
95 \end{alltt}
96
97 After this code executes, we might expect \uw{b} to always be equal to \uw{a}.
98 but if \uw{foo} is a global variable, \kw{MPI\_Recv} may block and 
99 \uw{foo} could be changed by another thread.
100
101 For example, if two threads execute this program, they could interleave like:
102
103 \vspace{0.1in}
104 \begin{tabular}{|l|l|}\hline
105 \em{Thread 1} & \em{Thread 2}\\
106 \hline
107 \uw{foo}=1 & \\
108 block in MPI\_Recv & \\
109  & \uw{foo}=2 \\
110  & block in MPI\_Recv \\
111 \uw{b}=\uw{foo} & \\
112 \hline\end{tabular}
113 \vspace{0.1in}
114
115 At this point, thread 1 might expect \uw{b} to be 1; but it will actually be 2.
116 From the point of view of thread 1, the global variable \uw{foo} suddenly
117 changed its value during the call to \kw{MPI\_Recv}.
118
119 There are several possible solutions to this problem:
120
121 \begin{itemize}
122 \item Never use global variables---only use parameters or local variables.  
123 This is the safest and most general solution.
124 One standard practice is to collect all the globals into a C struct or 
125 Fortran type named ``Globals", and pass a pointer to this object to all
126 your subroutines.  This also combines well with the pup method for doing
127 migration-based load balancing, as described in Section~\ref{sec:pup}.
128
129 \item Never write {\em different} values to global variables.  If every thread
130 writes the same value, global variables can be used safely.  For example,
131 you might store some parameters read from a configuration file like the 
132 simulation timestep $\Delta t$.  See Section~\ref{sec:readonlyglobal}
133 for another, more convenient way to set such variables.
134
135 \item Never issue a blocking call while your global variables are set.
136 This will not work on a SMP version of Charm++, where several processors
137 may share a single set of global variables.
138 Even on a non-SMP version, this is a dangerous solution, because someday 
139 someone might add a blocking call while the variables are set.  
140 This is only a reasonable solution when calling legacy code or 
141 using old serial libraries that might use global variables.
142 \end{itemize}
143
144 The above only applies to routines that run in the parallel context.
145 There are no restrictions on global variables for serial context
146 code.
147
148
149
150 \subsection{Input/Output}
151 \label{sec:io}
152
153 In the parallel context, there are several limitations on open
154 files.  First, several threads may run on one processor, so
155 Fortran Logical Unit Numbers are shared by all the threads on
156 a processor.  Second, open files are left behind when a thread 
157 migrates to another processor---it is a crashing error to open a 
158 file, migrate, then try to read from the file.
159
160 Because of these restrictions, it is best to open files only when
161 needed, and close them as soon as possible.  In particular, it
162 is best if there are no open files whenever you make blocking calls.
163
164
165 \subsection{Migration-Based Load Balancing}
166 \label{sec:migration}
167 \label{sec:isomalloc}
168
169 The \charmpp\ runtime framework includes an automatic run-time load balancer,
170 which can monitor the performance of your parallel program.
171 If needed, the load balancer can ``migrate'' threads from heavily-loaded
172 processors to more lightly-loaded processors, improving the load balance and
173 speeding up the program.  For this to be useful, you need to pass the 
174 link-time argument \kw{-balancer} \uw{B} to set the load balancing algorithm,
175 and the run-time argument \kw{+vp} \uw{N} (use \uw{N} virtual processors)
176 to set the number of threads.
177 The ideal number of threads per processor depends on the problem, but
178 we've found five to a hundred threads per processor to be a useful range.
179
180 When a thread migrates, all its data must be brought with it.
181 ``Stack data'', such as variables declared locally in a subroutine,
182 will be brought along with the thread automatically.  Global data,
183 as described in Section~\ref{sec:global}, is never brought with the thread
184 and should generally be avoided.
185
186 ``Heap data'' in C is structures and arrays allocated using \kw{malloc} or \kw{new};
187 in Fortran, heap data is TYPEs or arrays allocated using \kw{ALLOCATE}.
188 To bring heap data along with a migrating thread, you have two choices:
189 write a pup routine or use isomalloc.  Pup routines are described in 
190 Section~\ref{sec:pup}.
191
192 {\em Isomalloc} is a special mode which controls the allocation of heap data.  
193 You enable isomalloc allocation using the link-time flag ``-memory isomalloc''.  
194 With isomalloc, migration is completely transparent---all your allocated data 
195 is automatically brought to the new processor.  The data will be unpacked at the same
196 location (the same virtual addresses) as it was stored originally; so even
197 cross-linked data structures that contain pointers still work properly.
198
199 The limitations of isomalloc are:
200 \begin{itemize}
201 \item Wasted memory.  Isomalloc uses a special interface\footnote{
202 The interface used is \kw{mmap}.} to aquire memory, and the finest granularity
203 that can be aquired is one page, typically 4KB.  This means if you allocate
204 a 2-entry array, isomalloc will waste an entire 4KB page.  We should eventually 
205 be able to reduce this overhead for small allocations.
206
207 \item Limited space on 32-bit machines.  Machines where pointers are 32 bits
208 long can address just 4GB ($2^32$ bytes) of virtual address space.  Additionally, 
209 the operating system and conventional heap already use a significant amount 
210 of this space; so the total virtual address space available is typically under 1GB.  
211 With isomalloc, all processors share this space, so with just 20 processors
212 the amount of memory per processor is limited to under 50MB!  This is an 
213 inherent limitation of 32-bit machines; to run on more than a few processors you 
214 must use 64-bit machines or avoid isomalloc.
215 \end{itemize}
216
217
218
219 \section{Advanced \tcharm{} Programming}
220 The preceeding features are enough to write simple programs
221 that use \tcharm{}-based frameworks.  These more advanced techniques
222 provide the user with additional capabilities or flexibility.
223
224
225 \subsection{Writing a Pup Routine}
226 \label{sec:pup}
227
228 The runtime system can automatically move your thread stack to the new
229 processor, but unless you use isomalloc, you must write a pup routine to 
230 move any global or heap-allocated data to the new processor.  A pup
231 (Pack/UnPack) routine can perform both packing (converting your data into a
232 network message) and unpacking (converting the message back into your data).  
233 A pup routine is passed a pointer to your data block and a
234 special handle called a ``pupper'', which contains the network message.  
235
236 In a pup routine, you pass all your heap data to routines named \kw{pup\_}\uw{type} or \kw{fpup\_}\uw{type}, where
237 \uw{type} is either a basic type (such as int, char, float, or double) or an array
238 type (as before, but with a ``s'' suffix).  Depending on the direction of
239 packing, the pupper will either read from or write to the values you pass--
240 normally, you shouldn't even know which.  The only time you need to know the
241 direction is when you are leaving a processor, or just arriving.
242 Correspondingly, the pupper passed to you may be deleting (indicating that you
243 are leaving the processor, and should delete your heap storage after packing),
244 unpacking (indicating you've just arrived on a processor, and should allocate
245 your heap storage before unpacking), or neither (indicating the system is
246 merely sizing a buffer, or checkpointing your values).
247
248 pup functions are much easier to write than explain-- a simple C heap block
249 and the corresponding pup function is:
250
251 \begin{alltt}
252      typedef struct \{
253        int n1;/*Length of first array below*/
254        int n2;/*Length of second array below*/
255        double *arr1; /*Some doubles, allocated on the heap*/
256        int *arr2; /*Some ints, allocated on the heap*/
257      \} my_block;
258  
259      void pup_my_block(pup_er p,my_block *m)
260      \{
261        if (pup_isUnpacking(p)) \{ /*Arriving on new processor*/
262          m->arr1=malloc(m->n1*sizeof(double));
263          m->arr2=malloc(m->n2*sizeof(int));
264        \}
265        pup_doubles(p,m->arr1,m->n1);
266        pup_ints(p,m->arr2,m->n2);
267        if (pup_isDeleting(p)) \{ /*Leaving old processor*/
268          free(m->arr1);
269          free(m->arr2);
270        \}
271      \}
272 \end{alltt}
273
274 This single pup function can be used to copy the \kw{my\_block} data into a
275 message buffer and free the old heap storage (deleting pupper); allocate
276 storage on the new processor and copy the message data back (unpacking pupper);
277 or save the heap data for debugging or checkpointing.
278
279 A Fortran block TYPE and corresponding pup routine is as follows:
280
281 \begin{alltt}
282      MODULE my_block_mod
283        TYPE my_block
284          INTEGER :: n1,n2x,n2y
285          DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:) :: arr1
286          INTEGER, ALLOCATABLE, DIMENSION(:,:) :: arr2
287        END TYPE
288      END MODULE
289  
290      SUBROUTINE pup_my_block(p,m)
291        IMPLICIT NONE
292        USE my_block_mod
293        USE pupmod
294        INTEGER :: p
295        TYPE(my_block) :: m
296        IF (fpup_isUnpacking(p)) THEN
297          ALLOCATE(m%arr1(m%n1))
298          ALLOCATE(m%arr2(m%n2x,m%n2y))
299        END IF
300        call fpup_doubles(p,m%arr1,m%n1)
301        call fpup_ints(p,m%arr2,m%n2x*m%n2y)
302        IF (fpup_isDeleting(p)) THEN
303          DEALLOCATE(m%arr1)
304          DEALLOCATE(m%arr2)
305        END IF
306      END SUBROUTINE
307 \end{alltt}
308
309
310 You indicate to \tcharm{} that you want a pup routine called using
311 the routine below.  An arbitrary number of blocks can be registered
312 in this fashion.
313
314 \vspace{0.2in}
315 \function{void TCHARM\_Register(void *block, TCharmPupFn pup\_fn)}
316 \function{SUBROUTINE TCHARM\_Register(block,pup\_fn)}
317     \args{TYPE(varies), POINTER :: block}
318     \args{SUBROUTINE :: pup\_fn}
319
320      Associate the given data block and pup function.  Can only be
321      called from the parallel context.  For the declarations above, you call
322      \kw{TCHARM\_Register} as:
323
324 \begin{alltt}
325           /*In C/C++ driver() function*/
326           my_block m;
327           TCHARM_Register(m,(TCharmPupFn)pup_my_block);
328  
329           !- In Fortran driver subroutine
330           use my_block_mod
331           interface
332             subroutine pup_my_block(p,m)
333               use my_block_mod
334               INTEGER :: p
335               TYPE(my_block) :: m
336             end subroutine
337           end interface
338           TYPE(my_block), TARGET :: m
339           call TCHARM_Register(m,pup_my_block)
340 \end{alltt}
341
342      Note that the data block must be allocated on the stack. 
343      Also, in Fortran, the "TARGET" attribute must be used on the 
344      block (as above) or else the compiler may not update values during 
345      a migration, because it believes only it can access the block.
346
347 \vspace{0.2in}
348 \function{void TCHARM\_Migrate()}
349 \function{subroutine TCHARM\_Migrate()}
350
351      Informs the load balancing system that you are ready to be
352      migrated, if needed.  If the system decides to migrate you, the
353      pup function passed to \kw{TCHARM\_Register} will first be called with 
354      a sizing pupper, then a packing, deleting pupper.  Your stack and pupped
355      data will then be sent to the destination machine, where your pup
356      function will be called with an unpacking pupper.  \kw{TCHARM\_Migrate}
357      will then return.  Can only be called from in the parallel context.
358
359
360
361 \subsection{Readonly Global Variables}
362 \label{sec:readonlyglobal}
363
364 You can also use a pup routine to set up initial values for global
365 variables on all processors.  This pup routine is called with only
366 a pup handle, just after the serial setup routine, and just before 
367 any parallel context routines start.  The pup routine is never
368 called with a deleting pup handle, so you need not handle that case.
369
370 A C example is:
371 \begin{alltt}
372      int g_arr[17];
373      double g_f;
374      int g_n; /*Length of array below*/
375      float *g_allocated; /*heap-allocated array*/
376  
377      void pup_my_globals(pup_er p)
378      \{
379        pup_ints(p,g_arr,17);
380        pup_double(p,&g_f);
381        pup_int(p,&g_n);
382        if (pup_isUnpacking(p)) \{ /*Arriving on new processor*/
383          g_allocated=malloc(g_n*sizeof(float));
384        \}
385        pup_floats(p,g_allocated,g_n);
386      \}
387 \end{alltt}
388
389 A fortran example is:
390 \begin{alltt}
391      MODULE my_globals_mod
392        INTEGER :: g_arr(17)
393        DOUBLE PRECISION :: g_f
394        INTEGER :: g_n
395        SINGLE PRECISION, ALLOCATABLE :: g_allocated(:)
396      END MODULE
397  
398      SUBROUTINE pup_my_globals(p)
399        IMPLICIT NONE
400        USE my_globals_mod
401        USE pupmod
402        INTEGER :: p
403        call fpup_ints(p,g_arr,17)
404        call fpup_double(p,g_f)
405        call fpup_int(p,g_n)
406        IF (fpup_isUnpacking(p)) THEN
407          ALLOCATE(g_allocated(g_n))
408        END IF
409        call fpup_floats(p,g_allocated,g_n)
410      END SUBROUTINE
411 \end{alltt}
412
413
414 You register your global variable pup routine using the method below.
415 Multiple pup routines can be registered the same way.
416
417 \vspace{0.2in}
418 \function{void TCHARM\_Readonly\_globals(TCharmPupGlobalFn pup\_fn)}
419 \function{SUBROUTINE TCHARM\_Readonly\_globals(pup\_fn)}
420     \args{SUBROUTINE :: pup\_fn}
421
422
423
424 \section{Combining Frameworks}
425 \label{sec:combining}
426
427 This section describes how to combine multiple frameworks in a 
428 single application.  You might want to do this, for example,
429 to use AMPI communication inside a finite element method solver.
430
431 You specify how you want the frameworks to be combined by writing
432 a special setup routine that runs when the program starts.
433 The setup routine must be named TCHARM\_User\_setup.  If you declare a 
434 user setup routine, the standard framework setup routines (such
435 as the FEM framework's \kw{init} routine) are bypassed, and you
436 do all the setup in the user setup routine.
437
438 The setup routine creates a set of threads and then attaches frameworks
439 to the threads.  Several different frameworks can be attached to one thread set,
440 and there can be several sets of threads; however, the most frameworks
441 cannot be attached more than once to single set of threads. That is, a single
442 thread cannot have two attached AMPI frameworks, since the MPI\_COMM\_WORLD 
443 for such a thread would be indeterminate.
444
445 \vspace{0.2in}
446 \function{void TCHARM\_Create(int nThreads, TCharmThreadStartFn thread\_fn)}
447 \function{SUBROUTINE TCHARM\_Create(nThreads,thread\_fn)}
448     \args{INTEGER, INTENT(in) :: nThreads}
449     \args{SUBROUTINE :: thread\_fn}
450
451 Create a new set of \tcharm{} threads of the given size.  The threads will
452 execute the given function, which is normally your user code.  
453 You should call \kw{TCHARM\_Get\_num\_chunks()} 
454 to get the number of threads from the command line.  This routine can 
455 only be called from your \kw{TCHARM\_User\_setup} routine.
456
457 You then attach frameworks to the new threads.  The order in which
458 frameworks are attached is irrelevant, but attach commands always apply
459 to the current set of threads.
460   
461 To attach a chare array to the \tcharm{} array, use:
462
463 \function{CkArrayOptions TCHARM\_Attach\_start(CkArrayID *retTCharmArray,int *retNumElts)}
464 This function returns a CkArrayOptions object that will bind your chare array to the \tcharm{} array, in addition to returning the \tcharm{} array proxy and number of elements by reference. If you are using frameworks like AMPI, they will automatically attach themselves to the \tcharm{} array in their initialization routines.
465
466 \section{Command-line Options}
467 \label{sec:cla}
468
469 The complete set of link-time arguments relevant to \tcharm{} is:
470 \begin{description}
471 \item[-memory isomalloc] Enable memory allocation that will automatically
472 migrate with the thread, as described in Section~\ref{sec:isomalloc}.
473
474 \item[-balancer \uw{B}] Enable this load balancing strategy.  The
475 current set of balancers \uw{B} includes RefineLB (make only small changes
476 each time), MetisLB (remap threads using graph partitioning library), 
477 HeapCentLB (remap threads using a greedy algorithm), and RandCentLB
478 (remap threads to random processors).  You can only have one balancer.
479
480 \item[-module \uw{F}] Link in this framework.  The current set of frameworks
481 \uw{F} includes ampi, collide, fem, mblock, and netfem.  You can link in 
482 multiple frameworks.
483
484 \end{description}
485
486 The complete set of command-line arguments relevant to \tcharm{} is:
487
488 \begin{description}
489 \item[+p \uw{N}] Run on \uw{N} physical processors.
490
491 \item[+vp \uw{N}] Create \uw{N} ``virtual processors'', or threads.  This is
492 the value returned by TCharmGetNumChunks.
493
494 \item[++debug] Start each program in a debugger window.  See Charm++
495 Installation and Usage Manual for details.
496
497 \item[+tcharm\_stacksize \uw{N}] Create \uw{N}-byte thread stacks.  This
498 value can be overridden using TCharmSetStackSize().
499
500 \item[+tcharm\_nomig] Disable thread migration.  This can help determine
501 whether a problem you encounter is caused by our migration framework.
502
503 \item[+tcharm\_nothread] Disable threads entirely.  This can help determine
504 whether a problem you encounter is caused by our threading framework.
505 This generally only works properly when using only one thread.
506
507 \item[+tcharm\_trace \uw{F}] Trace all calls made to the framework \uw{F}.
508 This can help to understand a complex program.  This feature is not
509 available if \charmpp{} was compiled with CMK\_OPTIMIZE.
510
511 \end{description}
512
513 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 \section{Writing a library using TCharm}
515 \label{sec:tlib}
516
517 Until now, things were presented from the perspective of a user---one 
518 who writes a program for a library written on TCharm. This section gives an
519 overview of how to go about writing a library in Charm++ that uses TCharm.
520
521 \begin{itemize}
522 \item Compared to using plain MPI, TCharm provides the ability to 
523 access all of Charm++, including arrays and groups.
524
525 \item Compared to using plain Charm++,
526 using TCharm with your library automatically provides your users with a 
527 clean C/F90 API (described in the preceeding chapters) for basic thread
528 memory  managment, I/O, and migration.  It also allows you to use a convenient
529 "thread->suspend()" and "thread->resume()" API for blocking a thread,
530 and works properly with the load balancer, unlike CthSuspend/CthAwaken.
531 \end{itemize}
532
533 The overall scheme for writing a TCharm-based library "Foo" is:
534
535 \begin{enumerate}
536 \item You must provide a FOO\_Init routine that creates anything
537 you'll need, which normally includes a Chare Array of your own
538 objects.  The user will call your FOO\_Init routine
539 from their main work routine; and normally FOO\_Init routines 
540 are collective.
541
542 \item In your FOO\_Init routine, create your array bound it to the 
543 running TCharm threads, by creating it using the CkArrayOptions 
544 returned by TCHARM\_Attach\_start.  Be sure to only create the 
545 array once, by checking if you're the master before creating the
546 array.  
547
548 One simple way to make the non-master threads block until the corresponding
549 local array element is created is to use TCharm semaphores.  
550 These are simply a one-pointer slot you can assign using TCharm::semaPut
551 and read with TCharm::semaGet.  They're useful in this context
552 because a TCharm::semaGet blocks if a local TCharm::semaGet hasn't
553 yet executed.  
554
555 \begin{alltt}
556 //This is either called by FooFallbackSetuo mentioned above, or by the user
557 //directly from TCHARM\_User\_setup (for multi-module programs)
558 void FOO\_Init(void)
559 \{
560   if (TCHARM\_Element()==0) \{
561     CkArrayID threadsAID; int nchunks;
562     CkArrayOptions opts=TCHARM\_Attach\_start(&threadsAID,&nchunks);
563   
564   //actually create your library array here (FooChunk in this case)
565     CkArrayID aid = CProxy\_FooChunk::ckNew(opt);
566   \}
567   FooChunk *arr=(FooChunk *)TCharm::semaGet(FOO_TCHARM_SEMAID);
568 \}
569 \end{alltt}
570
571 \item Depending on your library API, you may have to
572 set up a thread-private variable(Ctv) to point to your library object. 
573 This is needed to regain context when you are called by the user.
574 A better design is to avoid the Ctv, and instead hand the user 
575 an opaque handle that includes your array proxy.
576
577 \begin{alltt}
578 //\_fooptr is the Ctv that points to the current chunk FooChunk and is only valid in 
579 //routines called from fooDriver()
580 CtvStaticDeclare(FooChunk *, \_fooptr);
581
582 /* The following routine is listed as an initcall in the .ci file */
583 /*initcall*/ void fooNodeInit(void)
584 \{
585   CtvInitialize(FooChunk*, \_fooptr);
586 \}
587 \end{alltt}
588
589 \item Define the array used by the library
590
591 \begin{alltt}
592 class FooChunk: public TCharmClient1D \{
593    CProxy\_FooChunk thisProxy;
594 protected:
595    //called by TCharmClient1D when thread changes
596    virtual void setupThreadPrivate(CthThread forThread)
597    \{
598       CtvAccessOther(forThread, \_fooptr) = this;
599    \}
600    
601    FooChunk(CkArrayID aid):TCharmClient1D(aid)
602    \{
603       thisProxy = this;
604       tCharmClientInit();
605       TCharm::semaPut(FOO_TCHARM_SEMAID,this);
606       //add any other initialization here
607    \}
608
609    virtual void pup(PUP::er &p) \{
610      TCharmClient1D::pup(p);
611      //usual pup calls
612    \}
613    
614    // ...any other calls you need...
615    int doCommunicate(...);
616    void recvReply(someReplyMsg *m);
617    ........
618 \}
619 \end{alltt}
620
621
622 \item Block a thread for communication using thread->suspend and
623 thread->resume
624
625 \begin{alltt}
626 int FooChunk::doCommunicate(...)
627 \{
628    replyGoesHere = NULL;
629    thisProxy[destChunk].sendRequest(...);
630    thread->suspend(); //wait for reply to come back
631    return replyGoesHere->data;
632 \}
633
634 void FooChunk::recvReply(someReplyMsg *m)
635 \{
636   if(replyGoesHere!=NULL) CkAbort("FooChunk: unexpected reply\\n");
637   replyGoesHere = m;
638   thread->resume(); //Got the reply -- start client again
639 \}
640 \end{alltt}
641
642
643 \item Add API calls. This is how user code running in the thread interacts
644 with the newly created library. Calls to TCHARM\_API\_TRACE macro must be 
645 added to the start of every user-callable method. In addition to tracing,
646 these disable isomalloc allocation. 
647
648 The charm-api.h macros CDECL, FDECL and
649 FTN\_NAME should be used to provide both C and FORTRAN versions of each 
650 API call.  You should use the "MPI capitalization standard", where the library
651 name is all caps, followed by a capitalized first word, with all subsequent 
652 words lowercase, separated by underscores.  This capitalization system is 
653 consistent, and works well with case-insensitive languages like Fortran.
654
655 Fortran parameter passing is a bit of an art, but basically for simple 
656 types like int (INTEGER in fortran), float (SINGLE PRECISION or REAL*4),
657 and double (DOUBLE PRECISION or REAL*8), things work well.  Single parameters
658 are always passed via pointer in Fortran, as are arrays.  Even though 
659 Fortran indexes arrays based at 1, it will pass you a pointer to the 
660 first element, so you can use the regular C indexing.  The only time Fortran
661 indexing need be considered is when the user passes you an index--the
662 int index will need to be decremented before use, or incremented before
663 a return.
664
665 \begin{alltt}
666 CDECL void FOO\_Communicate(int x, double y, int * arr) \{
667    TCHARM\_API\_TRACE("FOO\_Communicate", "foo"); //2nd parameter is the name of the library
668    FooChunk *f = CtvAccess(\_fooptr);
669    f->doCommunicate(x, y, arr);
670 \}
671
672 //In fortran, everything is passed via pointers
673 FDECL void FTN\_NAME(FOO_COMMUNICATE, foo_communicate)
674      (int *x, double *y, int *arr)
675 \{
676    TCHARM\_API\_TRACE("FOO_COMMUNICATE", "foo");
677    FooChunk *f = CtvAccess(\_fooptr);
678    f->doCommunicate(*x, *y, arr); 
679 \}
680 \end{alltt}
681
682 \end{enumerate}
683
684 \input{index}
685 \end{document}