Execution Environments

In our we have discussing Environment => Conceptual Models. Today, I am going to discuss about Environment => Execution Environments.

Execution Environments

The execution environment is a key component of any implemented real-time system. It supports the application, but also introduces overheads and constrains the facilities that the application can use. A full-blown operating system could be used to provide the execution environment, but this is usually rejected due to:
  • size of the OS (that is, memory occupancy);
  • efficiency of key functions (such as context switching);
  • complexity and hence reliability of the complete OS.
Thus, it means that execution environment is a type of node (or part of a node) that represents a particular execution platform, such as an operating system or a database management system. Execution environments are used to describe the context in which the execution of a model takes place. Execution environments are typically part of another node that models the computing hardware of a system.
In simple terms term ‘execution environment’ is used to mean those components that are used together with the application’s code to make the complete system: the processors, networks, operating systems and so on. The nature of the proposed execution environment will dictate whether a particular design will meet its real-time requirements. The execution environment has a significant impact on the timing properties of an application. Where there is a software kernel, the overheads incurred by the kernel must be taken into account during the schedule ability analysis of the application. The following characteristics are typical of many real-time software kernels:
  • The cost of a context switch between processes is not negligible and may not be a single value. The cost of a context switch to a higher-priority periodic process may be higher than a context switch from a process to a lower-priority process.
  • All context switch operations are non preemptive.
  • The cost of handling an interrupt (other than the clock) and releasing an application process is not insignificant. Furthermore, for DMA and channel program controlled devices, the impact of shared-memory access can have a nontrivial impact on worst-case performance; such devices are best avoided in hard real-time systems.
  • A clock interrupt (say every 10ms) could result in periodic processes being moved from a delay queue to the dispatch queue. The costs for this operation varies depending on the number of processes to be moved.
Language C has two execution environments are: freestanding environment and hosted environment. In both cases, program start-up occurs when a designated C function is called by the execution environment. All objects with static storage duration shall be initialized (set to their initial values) before program start-up. The manner and timing of such initialization are otherwise unspecified. Program termination returns control to the execution environment.
Executing the developer-written functions is only part of the process of executing a program. Initialization applies to all objects having file scope and objects in block scope that have internal linkage. The initial values may have been provided explicitly by the developer or implicitly by the implementation. Once set, these objects are never reinitialized again during the current program invocation, even if main is called recursively. It is guaranteed that all objects having file scope will have been initialized to some value prior to program start-up.
For objects defined at file scope the standard only supports initialization expressions whose value is known at translation-time. This means that there are no dependencies on the order of these initialization’s. It is not possible to write a conforming C program that can deduce the manner and timing of initialization. Floating-point constants, the representation of which can vary between hosts, may be stored in a canonical form in the program image, and be converted by start-up code to the representation used by the host. Program termination also causes all open files to be closed.

1. Freestanding environment

In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program start-up are implementation-defined. Any library facilities available to a freestanding program, other than the minimal set required by clause 4, are implementation-defined. The effect of program termination in a freestanding environment is implementation defined.
The parameters to the called function are defined by the implementation and can be very different from those defined here for main (in a hosted environment). If there is no operating system, there are not likely to be any command line parameters, but information may be passed into the function called. Without the benefit of an operating system, the issue of how to provide the ability to start-up different programs becomes important. Having available a set of functions, which can be selected among-st just prior to program startup, provides one solution.
In many cases there is no named program at all. Switching on, or resetting, the freestanding host causes the processor instruction pointer to be set to some predefined location in storage, whichever instructions are located at that and subsequent locations being executed. Traditionally there is a small bootstrap loader at this location, which copies a larger program from a storage device into memory and jumps to the start of that program (it might be a simple operating system). In other cases that storage device is ROM and the program will already be in memory at the predefined location. Translated program instructions are executed directly from the storage device. Once switched on, the host may have buttons that cause the processor to be reset to a different location, causing different functions to be invoked on start-up.

2. Hosted environment

This specification is the minimal set of requirements that a program can assume will be provided by a conforming hosted implementation. The application domain may influence developer expectations about the minimal functionality available. A hosted environment need not be provided, but shall conform to the following specifications if present are:

2.1 – Program Startup

The function called at program startup is named main. The implementation declares no prototype for this function.
Implementations use a variety of techniques to start executing a program image. These usually involve executing some internal, implementation-specific, function before main is called. The association between this internal function and main is usually made at link-time by having the internal function make a call to main, which is resolved by the linker in the same way as other function calls. There is no declaration of main in any system header, or internally within the translator. For this reason translators rarely check that the definition of main follows one of the two specifications given for it. A function named main is usually treated like any other developer-defined function. The question now arise Can we write a C Program without main?
Yes, we can write the program without main function such as:
#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
int begin(){
    printf("hello");
    return 0;
}
When you compile and run the above program it will run and produce “hello” as output but it is advised to start the program with main. Main function is responsible for the high-level organization of the program’s functionality, and typically has access to the command arguments given to the program when it was executed. The main function is generally the first programmer-written function run when a program starts, and is invoked directly from the system-specific initialization contained in crt0 or equivalent.
It shall be defined with a return type of int and with no parameters:
int main(void) { /* … */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* … */ }
or equivalent; or in some other implementation-defined manner.
The parameters of main are treated just like the parameters in any other developer-defined function. The parameters argc, argument count, and argv, argument vector, respectively give the number and value of the program’s command-line arguments. The names of argc and argv may be any valid identifier in C, but it is common convention to use these names. Unix (though not POSIX.1) and Microsoft Windows have a third argument giving the program’s environment, otherwise accessible through getenv in stdlib.h:
int main(int argc, char **argv, char **envp)
Mac OS X and Darwin have a fourth parameter containing arbitrary OS-supplied information, such as the path to the executing binary:
int main(int argc, char **argv, char **envp, char **apple)
The identifiers argc and argv are commonly used by developers as the names of the parameters to main. The Committee recognized that there is additional information that a host might need to pass to main on startup, but they did not want to mandate anything specific. Two arguments which are important must be present as 1st parameter and 2nd parameter as argc and argv.
If they are declared, the parameters to the main function shall obey the following constraints:
  • The value of argc shall be non-negative.
The value of argc, as set by the implementation on startup is non-negative. The parameter has type int and could be set to a negative value within the program. Most hosts have a limitation on the maximum number of characters that may be passed to a program on startup (via, for instance, the command line). This limit is also likely to be a maximum upper limit on the value of argc. Knowing that argc is always set to a non-negative value, a developer reading the code might expect it to always have a non-negative value. Assigning a negative value to argc as a flag to indicate a special condition is sometimes seen.
  • argv[argc] shall be a null pointer.
Some algorithmic styles prefer to decrement a count of the remaining elements. Some prefer to walk a data structure until a null pointer is encountered. The standard supports both styles.
  • If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
The storage occupied by the strings has static storage-duration. The host environment is likely to process the arguments first, possibly performing such operations as expanding wildcards and environment variables. A white-space character is usually used to delimit program parameters. Many hosts offer some form of quoting mechanism to allow any re-presentable character, in host environment, to be passed as a value to argv (including character sequences that contain white space). The behavior most often encountered is that the elements of argv, in increasing subscript order, correspond to the white-space delimited character sequences appearing on the command line in left-to-right order.
Unix (POSIX) defines _POSIX_ARG_MAX, in, as “The length of the arguments for one of the exec functions, in bytes, including environment data.” and requires that it have a value of at least 4,096. Under MS-DOS the command processor, command.com, reads a value on startup that specifies the maximum amount of the space to use for its environment (where command line information is held).
The argc/argv mechanism provides a simple-to-use, from both the applications ‘users’ point of view and the developer’s, method of passing information (usually frequently changing) to a program. The alternative being to use a file, read by the application, which would need to be created or edited every time options changed. This is not to say that an implementation might not choose to obtain the information by reading from a file.
Some older host environments convert, by default, all command line character input into a single case. A commonly occurring program argument is the name of a file. Unix filenames tend to be in lowercase and the file system is case-sensitive. Having an application to accept non-filename arguments in lowercase has a lower cost than insisting that filenames be in uppercase. Most modern hosts support the use of both upper and lowercase characters. The extent to which a program needs to take account of those cases where they might not both be available will depend on the information passed via argv and the likelihood that the program will need to be ported to such a host.
  • If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
What is the program name? Does it really important to provide?
It is usually thought of as the sequence of characters used to invoke the program, which in turn relates in some way to the program image. Under MS-DOS typing, abc on the command line causes the program abc.exe to be executed. In most implementations, the value of argv[0] in this case is abc.exe even though the extension .exe may not have appeared on the command line.
Unix based environments use the character sequence typed on the command line as the name of the program. This does not usually include the search path along which the program was found. For symbolic links the name of the symbolic link is usually used, not the name of the file linked to.
Most hosts can provide the name of the program via argv[0]. Not all host environments can provide information on the name of the currently executing program. This defines the term program parameters. It does not require that the value of the parameters come from the command line, although this is the background to the terminology.
#include <stdio.h>
int main(int argc, char *argv[]){
    printf("The program parameters were:\n");
    for (int a_index = 0; a_index < argc; a_index++){
        printf("%s\n", argv[a_index]);
    }
}
  • The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
Although the strings pointed to by the argv array are required to be modifiable, the array itself is not required to be modifiable. Calling main recursively (permitted in C90, but not in C99) does not cause the original values to be assigned to those parameters. The addresses of the storage used to hold the argv strings may be disjoint from the stack and heap storage areas assigned to a program on startup. Some implementations choose to place the program parameter strings in an area of storage specifically reserved, by the host environment, for program’s parameters.

2.2 – Program Execution

In a hosted environment, a program may use all the functions, macros, type definitions, and objects described in the library clause (clause 7).
There are no library subsets; C is a single implementation conformance level standard. However, although functions of the specified name may be present to link against, in translation phase 8, the functionality provided by an implementation’s library may vary (including doing nothing and effectively being optional). Some library functionality was known to be difficult, if not impossible, to implement on certain host environments. In these cases the library functions have minimal required functionality; for instance, signal handling. The C Standard, unlike POSIX, does not prohibit the use of functions, macros, type definitions, and objects from other standards, but such libraries must not change the behavior of any of the C-defined library functionality.

2.3 – Program Termination

If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.
The call to exit will invoke any functions that have been registered at exit function. This behavior is not the same as a return from main simply returning control to whatever startup function called it, which in turn calls exit. After main returns, any objects defined in it with automatic storage will no longer have storage reserved for them, rendering any access (i.e., in the functions registered at exit) to them as undefined behavior. The value returned is often used as the termination status of the executed program in the host environment. Many host environments provide a mechanism for testing this status immediately after program termination.
A translator can choose to special case functions defined with the name main or simply provide, where necessary, an implicit return of 0 for all functions returning type int. The return type can only be incompatible with int if main has been defined to return a different, incompatible, type. If main has a return type of void, an implementation may choose not to return any value. In this case, the standard does not guarantee that a call to the exit library function will return the requested status to the host environment.
Advertisements
Tagged , , , , , ,
%d bloggers like this: