Control Flow of Function Calls
Return to Detailed Explanations of p077
0
This is the entrance to the processing when a function is called.
k1 conatins the node number of the parse tree and produc[k1]
contains the production number of the production by which the node is to be reduced.
Production numbers 207 and 208 leads to this entrance. As shown in the
production list, the production 207 represents a function call with
some arguments, while the production 208 corresponds to a function call with no arguments.
The arguments that are to be passed the function are already pushed onto
the multi-purpose stack (mpstk).
Besides the entrance for function calls, this point is also serve as the entrance
when a user-defined function finishes the processsing and returns. In this case a
value 10 is pushed onto the mpstk.
i1 is the stack pointer that points to the elements which contain 0/k1 values.
A stack pointer i represents two integer values that are contained in mpstk[2*i]
and mpstk[2*i+1]. nmp is the stack pointer that point to the top of stack.
1
The case when the control flow returns from a user-defined function can be identified
by looking at the stack pointed to by i1+1. If its value is 10, it means the return
from a user-defined function. Else, a new function call.
2
We can identify from which user-defined function we have returned, by looking into the
top of memory stack mem[nmem-1].
The return value of the function is pushed onto the mpstk[].
The return value can be either a double or an int. It can be retrieved
from the particular places within the element on the memory stack.
Then the temporary memory areas that are allocated by the memory element mem[nmem-1] are
freed. Finally the memory element mem[nmem-1] itself is freed and the memory pointer
nmem is decremented.
3
If the value of the mpstk[] pointed to by i1+1 is 9, the control returned
from a user-defined function that implements a callback function. If this is the case, cb
is set to 1 and will be used for the later flow control.
4
The function name can be determined from the information contained in the mpstk[].
We compare the name of the called function with the list of user-defined functions.
The user-defined functions are listed in the struct array scop[].
The search ends up with k<nscop if the called function is a user-defined function.
5
This branch is to sort out a call to a user-defined function.
The cases other than a call to a user-defined function includes a call to an internal
function, a call to an IPC function and a return from a callback function.
6
The preparation for a call to a user-defined function starts with pushing a memory set
on to the memory stack. This can be acheved by allocating a memory area to the
variable mem[nmem].
Then initialization of the memory set takes place by first allocating the data areas for
various variable types.
The memory set and the associated data areas are initialized by the data contained in
the struct scop[k] for the function.
Just before exiting, the return address and the function entry address are pushed onto
the multi-purpose stack.
7
If the flow is not the return from a calback function, it is the call to a library
function. A library functions is either an internal function or an IPC function.
8
We test here if the called function is one of the internal functions. If this is the
case the variable j is set to 0.
9
For an IPC function, the corresponding function program is identified by its semaphore
number. The variable ipc is set to the semaphore number.
10
The internal function does not use IPC mechanism and does not have a corresponding
semaphore. The variable ipc is simply set to 0.
11
Arguments are set in a set of data structures that are common to both internal and
IPC functions.
12
The flow branches here accoding to whether the called function is internal or IPC.
13
If the call is for an internal function, the function func() is called.
14
If the flow is not the return from a callback function, the lengthy calling process of an
IPC function starts here.
15
Here, we move the calling parameters to the shared memory. The shared memory can be
accessed both by the GCS main program p077 and all the running function programs.
By raising the semaphore identified by the number in the variable ipc, the control
is passed to the intended function program. The GCS main program waites here for the
semaphore 0 to be raised.
16
The function program can report to the GCS main program that an error ocuured while
processing the called function by raising the semaphore 1.
17
The function program can request the GCS main program that the value of an input form field
to be passed by means of the shared memory by raising the semaphore 5 and specifying
the name of the input form field in the predifined field of the shared memory.
18
The input to the function program is transferred to the shared memory here.
19
The semaphore 6 is raised here to signal the function program that the requested data
is in the shared memory ready to be picked up.
20
The function program can request for another input by rasing the semaphore 5 again.
21
If the flow is the return from a callback function or the semahore 3 is raised,
the flow branches to the processing of a callback.
22
If cb is 0 at this point, a new callback is initiated by the function program by
raising the semaphore 3. If cb is 1, this is the return pass from a callback
function.
23
Preparation for the call to a user-defined callback function is made here.
The return address and the user-defined function call setting are pushed onto
the multi-purpose stack. The argument values to the callback function are also
pushed onto the mpstk[].
24
Here we put the results from the called callback function in the shared memory.
25
Raising the semaphore 2 here signals the function program that the callback is finished
and the result data are in the shared memory ready for the function program to pick up.
After passing the control to the function program, the main program p077
waites for the further call by watching the semaphore 0 to be raised.
26
If the further call from the function program is an another call to a callback function,
jump back to the start of the callback section.
27
If the flow is for the start of a callback, it falls through to the exit.
Otherwise, as this point is immediately after the semaphore 0 is raised and hence
the control is passed from the function program, we will continue processing
the matters the function program requested.
28
Here, we test if the semaphore 2 is raised. The function program places the output data
that are to be sent to the client in the shared memory and raises semaphore 2. Then
it raises the semaphore 0, for which the main CGI program has been waiting to be raised.
29
The main program, p077, relays the data from the function program to the output chain.
30
The main program raises the semaphore 3 to notify the function program that the data
have been sent out, and then waites by watching the semaphore 0 to be raised again.
31
When the semaphore 0 is raised, the control is passed to the main program from the
function program. The first thing the main program does is to test if the semaphore 3
is raised. If it is raised, it means that further output data are contained in the
shared memory.
If the semaphore 2 is not raised, it means that this is the return from the IPC function.
32
When the control finally returned from an IPC function, the result data are placed
in the shared memory. We have to move those data to the appropriate places in the
main program before exiting.
33
In the case of the call to a callback function, the flow simply falls through this branch.
The other cases that enters this branch are the return from an internal function or from
an IPC function.
34
The common processings to both an internal function and an IPC function are carried out here.
These are simply to push the returned value on to the multi-purpose stack.