===========
PROCESS.H
===========
Functions
=========
abort
_cexit
_c_exit
execl
execle
execlp
execlpe
execv
execve
execvp
execvpe
exit
_exit
getpid
spawnl
spawnle
spawnlp
spawnlpe
spawnv
spawnve
spawnvp
spawnvpe
system
Constants, data types, and global variables
===========================================
P_NOWAIT
P_OVERLAY
P_WAIT
_psp
See Also
========
List of all Header files
==========
ASSERT.H
==========
Includes
========
STDIO.H
STDLIB.H
Functions
=========
assert
See Also
========
List of all Header files
==========
SETJMP.H
==========
Functions
=========
longjmp
setjmp
Constants, data types, and global variables
===========================================
jmp_buf
See Also
========
List of all Header files
==========
SIGNAL.H
==========
Functions
=========
raise
signal
Constants, data types, and global variables
===========================================
predefined signal handlers
sig_atomic_t type
SIG_DFL
SIG_ERR
SIG_ING
SIGABRT
SIGFPE
SIGILL
SIGINT
SIGSEGV
SIGTERM
See Also
========
List of all Header files
P_xxxx <PROCESS.H>
========
Modes used by the spawn function.
Constant | Meaning
-----------+---------------------------------------------------------
P_WAIT | Child runs separately, parent waits until exit
P_NOWAIT | Child and parent run concurrently (Not implemented)
P_OVERLAY | Child replaces parent so that parent no longer exists
===================
exec... functions <PROCESS.H>
===================
Enable your program to load and run other files (child processes)
Use these execl... functions when you know
how many separate arguments you'll have:
Declaration:
* int execl (char *path, char *arg0, ..., NULL);
* int execle (char *path, char *arg0, ..., NULL, char **env);
* int execlp (char *path, char *arg0, ...);
* int execlpe(char *path, char *arg0, ..., NULL, char **env);
Use these execv... functions when you don't
know in advance how many separate arguments
you will have:
Declaration:
* int execv (char *path, char *argv[]);
* int execve (char *path, char *argv[], char **env);
* int execvp (char *path, char *argv[]);
* int execvpe(char *path, char *argv[], char **env);
Remarks:
When an exec... call succeeds, the child
process overlays the parent process. There
must be sufficient memory available for
loading and executing the child process.
The l, v, e, and p suffixes added to "exec"
specify certain capabilities of the exec...
function.
Argument | What It Is/Does
----------+----------------------------------------------------------------
path | File name of the called child process
argN | Argument pointer(s) passed as separate arguments
argv[N] | Argument pointer(s) passed as an array of pointers
env | Array of character pointers.
The exec... functions search for path using
the standard DOS search algorithm.
When an exec... function call is made, any
open files remain open in the child process.
Return Value:
* On success, the functions do not return.
* On error, the functions return -1 and set
errno to one of the following:
E2BIG Arg list too long
EACCES Permission denied
EMFILE Too many open files
ENOENT Path or file name not found
ENOEXEC Exec format error
ENOMEM Not enough core
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | | | | |
+-----+------+---------+--------+----------+
See Also:
searchpath
spawn...
system
Examples:
execl example
execlp example
execle example
execlpe example
execv example
execvp example
execve example
execvpe example
execl example
===============
#include <stdio.h>
#include <process.h>
int main(int argc, char *argv[])
{
int loop;
printf("%s running...\n\n", argv[0]);
if (argc == 1) { /* check for only one command-line parameter */
printf("%s calling itself again...\n", argv[0]);
execl(argv[0], argv[0], "ONE", "TWO", "THREE", NULL);
perror("EXEC:");
exit(1);
}
printf("%s called with arguments:\n", argv[0]);
for (loop = 1; loop <= argc; loop++)
puts(argv[loop]); /* Display all command-line parameters */
return 0;
}
execlp example
================
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main( int argc, char *argv[])
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
execlp("CHILD.EXE", "CHILD.EXE", "arg1", "arg2", NULL);
perror("exec error");
exit(1);
return 0;
}
execle example
================
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
int loop;
char *new_env[] = { "TESTING", NULL };
printf("%s running...\n\n", argv[0]);
if (argc == 1) { /* check for only one command-line parameter */
printf("%s calling itself again...\n", argv[0]);
execle(argv[0], argv[0], "ONE", "TWO", "THREE", NULL, new_env);
perror("EXEC:");
exit(1);
}
printf("%s called with arguments:\n", argv[0]);
for (loop = 1; loop <= argc; loop++)
puts(argv[loop]); /* display all command-line parameters */
/* display the first environment parameter */
printf("value of env[0]: %s\n",env[0]);
return 0;
}
execlpe example
=================
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[], char **envp )
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
execlpe("CHILD.EXE", "CHILD.EXE", "arg1", "arg2", NULL, envp);
perror("exec error");
exit(1);
return 0;
}
execv example
===============
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; i++)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
execv("CHILD.EXE", argv);
perror("exec error");
exit(1);
return 0;
}
execve example
================
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[], char **envp)
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
execve("CHILD.EXE", argv, envp);
perror("exec error");
exit(1);
return 0;
}
execvp example
================
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
execvp("CHILD.EXE", argv);
perror("exec error");
exit(1);
return 0;
}
execvpe example
=================
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[], char **envp)
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
execvpe("CHILD.EXE", argv, envp);
perror("exec error");
exit(1);
return 0;
}
l, v, e, and p suffixes
=========================
The l, v, e, and p suffixes specify certain
capabilities of the exec... and spawn...
functions.
Each function in these families must have one
of the two argument-specifying suffixes
(either l or v):
Suffix| Capabilities of the exec... or spawn... Function
------+-------------------------------------------------------------------
l | Argument pointers (arg0, ..., argN) passed as separate arguments
v | Argument pointers (argv[0], ..., argv[N]) passed as an array
| of pointers
The environment inheritance (e) and path
search (p) suffixes are optional:
Suffix| Capabilities of the exec... or spawn... Function
------+-------------------------------------------------------------------
e | The function passes the env argument to the child process to
| alter the child's environment. Without the "e" suffix, the child
| inherits the parent's environment.
|
p | The function searches for the child process in the directories
| specified by the DOS environment variable PATH.
Standard DOS Search Algorithm
===============================
Argument = FILENAME (no dot, no extension)
==========================================
1) If no explicit extension is given, the
function searches for the file as given.
2) If the file is not found, the function
adds .COM and searches again.
3) If that search is not successful, it adds
.EXE and searches one last time.
Argument = FILENAME. or FILENAME.EXT
====================================
If an explicit extension or a period is
given, the function searches for the file
exactly as given.
argN and argv[N] arguments to exec... and spawn...
====================================================
The exec... and spawn... functions must pass
at least one argument (arg0 or argv[0]) to
the child process.
This argument is, by convention, a copy of
path. (Using a different value for this 0th
argument won't produce an error.)
* Under DOS 3.x, the variable path is available for the child process.
* Under earlier versions of DOS, the child process can't use the passed
value of the 0th argument (arg0 or argv[0]).
"l" Suffix
==========
When you use the "l" suffix with exec... or
spawn..., arg0 usually points to path, and
(arg1, ..., argN) point to character strings
that form the new list of arguments.
A mandatory null following argN marks the end
of the list.
The combined length of
(arg0 + arg1 + ... + argN)
or of
(argv[0] + argv[1] + ... + argv[N])
must be less than 128 bytes (including space
characters that separate the arguments). Null
terminators are not counted.
env argument to exec... and spawn...
======================================
When you use the "e" suffix with exec... or
spawn..., you pass a list of new environment
settings through the argument env.
*env is an array of character pointers. The
last element in env is null.
Each element points to a null-terminated
character string of the form
envvar = value
* envvar is the name of an environment variable
* value is the string value to which envvar is set
When *env is null, the child inherits the
parent's environment settings.
=========
_exit <PROCESS.H, STDLIB.H>
_c_exit <PROCESS.H>
=========
* _exit terminates the program
* _c_exit performs _exit cleanup without terminating the program
Declaration:
* void _exit(int status);
* void _c_exit(void);
Remarks:
_exit terminates execution without closing
any files, flushing any output, or calling
any exit functions.
_c_exit performs the same cleanup as _exit,
except that it does not terminate the calling
process.
_c_exit restores interrupt vectors altered
by the startup code, but performs no other
cleanup.
status
======
With _exit, status is provided for the
calling process as the exit status of the
process.
Typically a value of 0 indicates a normal
exit, and a non-zero value indicates some
error.
Return Value: None
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
_exit | Yes | Yes | Yes | | |
_c_exit | Yes | | Yes | | |
+-----+------+---------+--------+----------+
See Also:
abort
atexit
_cexit
exec...
exit
_dos_keep
signal
spawn...
Examples:
_exit example
_c_exit example
_exit example
===============
#include <stdlib.h>
#include <stdio.h>
void done(void);
int main(void)
{
atexit(done);
_exit(0);
return 0;
}
void done()
{
printf("hello\n");
}
_c_exit example
=================
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <dos.h>
main()
{
int fd;
char c;
if ((fd = open("_c_exit.c",O_RDONLY)) < 0)
{
printf("Unable to open _c_exit.c for reading\n");
return 1;
}
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d before _c_exit\n",fd);
else
printf("Successfully read from open file handle %d before _c_exit\n",fd);
printf("Interrupt zero vector before _c_exit = %Fp\n",_dos_getvect(0));
_c_exit();
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d after _c_exit\n",fd);
else
printf("Successfully read from open file handle %d after _c_exit\n",fd);
printf("Interrupt zero vector after _c_exit = %Fp\n",_dos_getvect(0));
return 0;
}
=========
_cexit, <PROCESS.H>
exit <PROCESS.H, STDLIB.H>
=========
* exit terminates the program
* _cexit performs exit cleanup without terminating the program
Declaration:
* void exit(int status);
* void _cexit(void);
Remarks:
exit terminates the calling process. Before
termination, exit does the following:
* closes all files
* writes buffered output (waiting to be output)
* calls any registered "exit functions" (posted with atexit)
_cexit performs the same cleanup as exit,
except that it does not close files or
terminate the calling process.
_cexit restores interrupt vectors altered by
the startup code.
status
======
With exit, status is provided for the calling
process as the exit status of the process.
Typically a value of 0 indicates a normal
exit, and a non-zero value indicates some
error.
You use the following to set status:
status | Indicates
--------------+--------------------------------------------------
EXIT_SUCCESS | Normal program termination
EXIT_FAILURE | Abnormal program termination. Signal to operating
| system that program has terminated with an error.
Return Value: None
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
_cexit | Yes | | Yes | | |
exit | Yes | Yes | Yes | Yes | |
+-----+------+---------+--------+----------+
See Also:
abort
atexit
_c_exit
_dos_keep
exec...
_exit
keep
signal
spawn...
Examples:
_cexit example
exit example
exit example
==============
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>
int main(void)
{
int status;
printf("Enter either 1 or 2\n");
status = getch();
/* Sets DOS errorlevel */
exit(status - '0');
/* Note: this line is never reached */
return 0;
}
_cexit example
================
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <dos.h>
main()
{
int fd;
char c;
if ((fd = open("_cexit.c",O_RDONLY)) < 0)
{
printf("Unable to open _cexit.c for reading\n");
return 1;
}
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d before _cexit\n",fd);
else
printf("Successfully read from open file handle %d before _cexit\n",fd);
printf("Interrupt zero vector before _cexit = %Fp\n",_dos_getvect(0));
_cexit();
if (read(fd,&c,1) != 1)
printf("Unable to read from open file handle %d after _cexit\n",fd);
else
printf("Successfully read from open file handle %d after _cexit\n",fd);
printf("Interrupt zero vector after _cexit = %Fp\n",_dos_getvect(0));
return 0;
}
========
getpid <PROCESS.H>
========
Gets the process ID of the program
Remarks:
getpid is a macro that gets the process ID of
the program. A process ID uniquely identifies
a program.
This concept is borrowed from multitasking
operating systems like UNIX, where each
process is associated with a unique process
number.
Return Value:
Returns the segment value of the PSP (program
segment prefix).
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | Yes | Yes | | |
+-----+------+---------+--------+----------+
Example:
#include <stdio.h>
#include <process.h>
int main()
{
printf("This program's process identification number (PID) "
"number is %X\n", getpid());
printf("Note: under DOS it is the PSP segment\n");
return 0;
}
====================
spawn... functions <PROCESS.H>
====================
Enable your programs to run other files (child processes). spawn...
functions return control to your program when the child processes finish.
Use these spawn... functions when you know
how many separate arguments you'll have:
Declaration:
* int spawnl (int mode, char *path, char *arg0, ..., NULL);
* int spawnle (int mode, char *path, char *arg0, ..., NULL, char *envp[]);
* int spawnlp (int mode, char *path, char *arg0, ..., NULL);
* int spawnlpe(int mode, char *path, char *arg0, ..., NULL, char *envp[]);
Use these spawn... functions when you don't
know how many separate arguments you'll have:
Declaration:
* int spawnv (int mode, char *path, char *argv[]);
* int spawnve (int mode, char *path, char *argv[], char *envp[]);
* int spawnvp (int mode, char *path, char *argv[]);
* int spawnvpe(int mode, char *path, char *argv[], char *envp[]);
Remarks:
The functions in the spawn... family create
and run (execute) other files, known as child
processes. There must be sufficient memory
available for loading and executing a child
process.
The l, v, e, and p suffixes added to "spawn"
specify certain capabilities of the spawn...
function.
Argument | What It Is/Does
----------+----------------------------------------------------------------
mode | Determines what action the calling function (parent process)
| takes after the spawn... call.
path | File name of the called child process
argN | Argument pointer(s) passed as separate arguments
argv[N] | Argument pointer(s) passed as an array of pointers
envp | Array of character pointers.
The spawn... functions search for path using
the standard DOS search algorithm.
When a spawn... function call is made, any
open files remain open in the child process.
If the child specifically calls exit with a
non-zero argument, its exit status can be set
to a non-zero value.
Return Value:
* On a successful execution, the spawn... functions return the child
process's exit status (0 for a normal termination).
* On error (the process can't be spawned successfully), the spawn...
functions return -1, and set errno to one of the following:
E2BIG Arg list too long
EINVAL Invalid argument
ENOENT Path or file name not found
ENOEXEC Exec format error
ENOMEM Not enough core
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | | | | |
+-----+------+---------+--------+----------+
See Also:
_exit
_fpreset
abort
atexit
exec
exit
searchpath
system
Examples:
spawnl example
spawnlp example
spawnle example
spawnlpe example
spawnv example
spawnvp example
spawnve example
spawnvpe example
mode argument of the spawn... functions
=========================================
These are the possible values of mode:
Constant | Meaning
-----------+--------------------------------------------------------------
P_WAIT | Puts parent process "on hold" until child process completes
| execution.
P_NOWAIT | Continues to run parent process while child process runs.
P_OVERLAY | Overlays child process in memory location formerly occupied
| by parent. Same as an exec... call.
P_NOWAIT is currently not available; using it
generates an error.
spawnl example
================
#include <process.h>
#include <stdio.h>
#include <conio.h>
void spawnl_example(void)
{
int result;
clrscr();
result = spawnl(P_WAIT, "bcc.exe", NULL);
if (result == -1)
{
perror("Error from spawnl");
exit(1);
}
}
void spawnle_example(void)
{
int result;
clrscr();
result = spawnle(P_WAIT, "bcc.exe", NULL, NULL);
if (result == -1)
{
perror("Error from spawnle");
exit(1);
}
}
int main(void)
{
spawnl_example();
spawnle_example();
return 0;
}
spawnle example
=================
#include <process.h>
#include <stdio.h>
#include <conio.h>
void spawnl_example(void)
{
int result;
clrscr();
result = spawnl(P_WAIT, "bcc.exe", NULL);
if (result == -1)
{
perror("Error from spawnl");
exit(1);
}
}
void spawnle_example(void)
{
int result;
clrscr();
result = spawnle(P_WAIT, "bcc.exe", NULL, NULL);
if (result == -1)
{
perror("Error from spawnle");
exit(1);
}
}
int main(void)
{
spawnl_example();
spawnle_example();
return 0;
}
spawnlp example
=================
/* spawnlp example */
#include <process.h>
#include <stdio.h>
#include <errno.h>
void main(int argc, char *argv[])
{
int i;
printf("Command line arguments:\n");
for (i=0; i<argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
spawnlp(P_WAIT, "C:\\BORLANDC\\BIN\\BCC.EXE", argv[1], argv[2], NULL);
perror("exec error");
exit(1);
}
spawnlpe example
==================
/* spawnlpe example */
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main( int argc, char *argv[], char **envp )
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
spawnlpe(P_WAIT, "C:\\BORLANDC\\BIN\\BCC.EXE", argv[1], argv[2], NULL, envp);
perror("exec error");
exit(1);
return 0;
}
spawnv example
================
/* spawnv example */
#include <process.h>
#include <stdio.h>
#include <errno.h>
void main(int argc, char *argv[])
{
int i;
printf("Command line arguments:\n");
for (i=0; i<argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
spawnv(P_WAIT,"C:\\BORLANDC\\BIN\\BCC.EXE", argv);
perror("exec error");
exit(1);
}
spawnve example
=================
/* spawnve example */
#include <process.h>
#include <stdio.h>
#include <errno.h>
void main(int argc, char *argv[], char **envp)
{
int i;
printf("Command line arguments:\n");
for (i=0; i<argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
spawnve(P_WAIT, "C:\\BORLANDC\\BIN\\TDMEM.EXE", argv, envp);
perror("exec error");
exit(1);
}
spawnvp example
=================
/* spawnvp example */
#include <process.h>
#include <stdio.h>
#include <errno.h>
void main(int argc, char *argv[])
{
int i;
printf("Command line arguments:\n");
for (i=0; i<argc; ++i)
printf("[%2d] : %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
spawnvp(P_WAIT, "C:\\BORLANDC\\BIN\\BCC.EXE", argv);
perror("exec error");
exit(1);
}
spawnvpe example
==================
/* spawnvpe example */
#include <process.h>
#include <stdio.h>
#include <errno.h>
int main( int argc, char *argv[], char **envp )
{
int i;
printf("Command line arguments:\n");
for (i=0; i < argc; ++i)
printf("[%2d] %s\n", i, argv[i]);
printf("About to exec child with arg1 arg2 ...\n");
spawnvpe(P_WAIT, "C:\\BORLANDC\\BIN\\BCC.EXE", argv, envp);
perror("exec error");
exit(1);
return 0;
}
========
system <PROCESS.H, STDLIB.H>
========
Issues a DOS command
Declaration: int system(const char *command);
Remarks:
system invokes the DOS command interpreter
file from inside an executing C program to
execute a DOS command, batch file, or other
program named by the string "command".
To be located and executed, the program must
be in the current directory or in one of the
directories listed in the PATH string in the
environment.
Because the COMSPEC environment variable
is used to find the command interpreter file,
the command interpreter file does not need to
be in the current directory.
Return Value
* On success, returns 0
* On error, returns -1 and sets errno to
ENOENT, ENOMEM, E2BIG, or ENOEXEC.
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | Yes | | Yes | |
+-----+------+---------+--------+----------+
See Also:
_fpreset
exec...
searchpath
spawn...
Example:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
printf("About to spawn command interpreter and run a DOS command\n");
system("dir");
return 0;
}
NDEBUG <ASSERT.H>
========
NDEBUG means "Use #define to treat assert as
a macro or a true function".
Can be defined in a user program. If defined,
assert is a true function; otherwise assert
is a macro.
========
assert <ASSERT.H>
========
Tests a condition and possibly aborts.
Declaration: void assert(int test);
Remarks:
assert is a macro that expands to an if
statement.
If test evaluates to 0, assert prints this
message on stderr:
Assertion failed: test, file filename, line linenum
and calls abort to abort the program.
The filename and linenum listed in the
message are the source file name and line
number where the assert macro appears.
If you place the #define NDEBUG directive
("no debugging") in the source code before
the #include <ASSERT.H> directive, the assert
statement is commented out.
Return Value: None
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | Yes | Yes | Yes | |
+-----+------+---------+--------+----------+
See Also:
abort
Example:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
struct ITEM {
int key;
int value;
};
/* add item to list, make sure list is not null */
void additem(struct ITEM *itemptr) {
assert(itemptr != NULL);
/* add item to list */
}
int main(void)
{
additem(NULL);
return 0;
}
jmp_buf <SETJMP.H>
=========
A buffer of type jmp_buf is used to save and
restore the program task state.
typedef struct {
unsigned j_sp, j_ss,
unsigned j_flag, j_cs;
unsigned j_ip, j_bp;
unsigned j_di, j_es;
unsigned j_si, j_ds;
} jmp_buf[1];
=================
setjmp, longjmp <SETJMP.H>
=================
* setjmp sets up for a nonlocal goto
* longjmp performs a nonlocal goto
Declaration:
* int setjmp(jmp_buf jmpb);
* void longjmp(jmp_buf jmpb, int retval);
Remarks:
* setjmp captures the complete task state in
jmpb and returns 0.
NOTE: setjmp MUST be called before longjmp.
* A later call to longjmp with jmpb restores
the captured task state and returns in such a
way that setjmp appears to have returned with
the value retval.
NOTE: longjmp can't pass the value 0; if 0 is
passed in retval, longjmp will substitute 1.
Task State
==========
A task state consists of the following:
* all segment registers (CS, DS, ES, SS)
* register variables (SI, DI)
* stack pointer (SP)
* frame base pointer (BP)
* flags
A task state is complete enough that setjmp
and longjmp can be used to implement
coroutines.
The routine that calls setjmp and sets up
jmpb must still be active and can't have
returned before the longjmp is called. If it
has returned, the results are unpredictable.
setjmp is useful for dealing with errors and
exceptions encountered in a low-level
subroutine of a program.
If Your Program Is Overlaid
===========================
If your program is overlaid, you can't use
setjmp and longjmp to implement coroutines.
Normally, setjmp and longjmp save and restore
all the registers needed for coroutines, but
the overlay manager needs to keep track of
stack contents and assumes there is only one
stack.
When you implement coroutines, there are
usually either two stacks or two partitions
of one stack, and the overlay manager will
not track them properly.
You can have background tasks that run with
their own stacks or sections of stack, but
* you must ensure that the background tasks
do not invoke any overlaid code, and
* you must not use the overlay versions of
setjmp or longjmp to switch to and from
background.
When you avoid using overlay code or support
routines, the existence of the background
stacks does not disturb the overlay manager.
Return Value:
* setjmp returns 0 when it is initially
called. If the return is from a call to
longjmp, setjmp returns a non-zero value.
* longjmp does not return.
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | Yes | Yes | Yes | |
+-----+------+---------+--------+----------+
See Also:
ctrlbrk
signal
Example (for both functions):
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
void subroutine(jmp_buf);
int main(void)
{
int value;
jmp_buf jumper;
value = setjmp(jumper);
if (value != 0)
{
printf("Longjmp with value %d\n", value);
exit(value);
}
printf("About to call subroutine ... \n");
subroutine(jumper);
return 0;
}
void subroutine(jmp_buf jumper)
{
longjmp(jumper,1);
}
SIG_xxx <SIGNAL.H>
=========
Predefined functions for handling signals
generated by raise or by external events.
Name | Meaning
---------+----------------------------
SIG_DFL | Terminate the program
SIG_IGN | No action, ignore signal
SIG_ERR | Return error code
See Also:
signal
signal types
SIGxxxx <SIGNAL.H>
=========
Signal types used by raise and signal.
Signal |Note| Meaning | Default Action
---------+----+-----------------------------------+-----------------------
SIGABRT | (*)| Abnormal termination | = to calling _exit(3)
SIGFPE | | Bad floating-point operation | = to calling _exit(1)
| | Arithmetic error caused by |
| | division by 0, invalid operation, |
| | etc. |
SIGILL | (#)| Illegal operation | = to calling _exit(1)
SIGINT | | Control-C interrupt | Is to do an INT 23h
SIGSEGV | (#)| Invalid access to storage | = to calling _exit(1)
SIGTERM | (*)| Request for program termination | = to calling _exit(1)
(*) Signal types marked with a (*) aren't generated by DOS or Borland C++
during normal operation. However, they can be generated with raise.
(#) Signals marked by (#) can't be generated asynchronously on 8088 or
8086 processors but can be generated on some other processors (see
signal for details).
sig_atomic_t <SIGNAL.H>
==============
Atomic entity type.
=======
raise <SIGNAL.H>
=======
Sends software signal to the executing program
Declaration: int raise(int sig);
Remarks:
raise sends a signal of type sig to the
program.
* If the program has installed a signal
handler for the signal type specified by
sig, that handler will be executed.
* If no handler has been installed, the
default action for that signal type will
be taken.
Return Value
* On success, raise returns 0.
* Otherwise, returns non-zero.
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | Yes | Yes | Yes | |
+-----+------+---------+--------+----------+
See Also:
abort
signal
Example:
#include <signal.h>
int main(void)
{
int a, b;
a = 10;
b = 0;
if (b == 0)
/* preempt divide by zero error */
raise(SIGFPE);
a = a / b;
return 0;
}
========
signal <SIGNAL.H>
========
Specifies signal-handling actions
Declaration:
void (*signal(int sig, void (*func) (int sig[,int subcode])))(int);
Remarks:
Signals are raised when an exception
condition occurs or when raise is called.
signal determines how receipt of signal
number sig will be treated.
You can install a user-specified handler
routine or use one of the two predefined
handlers, SIG_DFL and SIG_IGN (declared in
SIGNAL.H).
Function |
Pointer | Meaning
---------+-----------------------------------
SIG_DFL | Terminates the program
SIG_ERR | Indicates error return from signal
SIG_IGN | Ignore this type signal
SIGNAL.H defines a type called sig_atomic_t,
the largest integer type the processor can
load or store atomically in the presence of
asynchronous interrupts. For the 8086 family,
this is a 16-bit word: a Borland C++ integer.
When a signal is generated by the raise
function or by an external event, the
following happens:
1) If a user-specified handler has been
installed for the signal, the action for
that signal type is set to SIG_DFL.
2) The user-specified function is called
with the signal type as the parameter.
User-specified handler functions can
terminate by a return or by a call to
abort, _exit, exit, or longjmp.
Borland C++ implements an extension to ANSI C
when the signal type is SIGFPE, SIGSEGV, or
SIGILL.
Return Value:
* On success (if the call succeeds), signal
returns a pointer to the previous handler
routine for the specified signal type.
* On failure (if the call fails), signal
returns SIG_ERR and sets errno to EINVAL.
Portability:
+ DOS + UNIX + Windows + ANSI C + C++ Only +
| Yes | | Yes | Yes | |
+-----+------+---------+--------+----------+
See Also:
_control87
abort
ctrlbrk
exit
longjmp
raise
setjmp
Example:
/* This example installs a signal handler routine for SIGFPE,
catches an integer overflow condition, makes an adjustment
to AX register, and returns. This example program MAY cause
your computer to crash, and will produce runtime errors
depending on which memory model is used.
*/
#pragma inline
#include <stdio.h>
#include <signal.h>
#ifdef __cplusplus
typedef void (*fptr)(int);
#else
typedef void (*fptr)();
#endif
void Catcher(int *reglist)
{
printf("Caught it!\n"); *(reglist + 8) = 3; /* make return AX = 3 */
}
int main(void)
{
signal(SIGFPE, (fptr)Catcher); /* cast Catcher to appropriate type */
asm mov ax,07FFFH /* AX = 32767 */
asm inc ax /* cause overflow */
asm into /* activate handler */
/* The handler set AX to 3 on return. If that hadn't happened,
there would have been another exception when the next 'into'
was executed after the 'dec' instruction. */
asm dec ax /* no overflow now */
asm into /* doesn't activate */
return 0;
}
Borland C++ extensions to signal
==================================
Borland C++ implements an extension to ANSI C
when the signal type is SIGFPE, SIGSEGV, or
SIGILL. The user-specified handler function
is called with either one or two extra
parameters.
Explicit call to raise
======================
If SIGFPE, SIGSEGV, or SIGILL has been raised
as the result of an explicit call to raise,
the user-specified handler is called with one
extra parameter, an integer specifying that
the handler is being explicitly invoked.
These are the explicit activation values for
SIGFPE, SIGSEGV, and SIGILL:
Signal Type | Meaning
-------------+-------------------
SIGFPE | FPE_EXPLICITGEN
SIGSEGV | SEGV_EXPLICITGEN
SIGILL | ILL_EXPLICITGEN
Floating-point Exception
========================
If SIGFPE is raised because of a
floating-point exception, the user handler is
called with one extra parameter that
specifies the FPE_xxx type of the signal.
Processor Exception
===================
If SIGSEGV, SIGILL, or the integer-related
variants of SIGFPE signals (FPE_INTOVFLOW or
FPE_INTDIV0) are raised as the result of a
processor exception, the user handler is
called with two extra parameters:
1) The SIGFPE, SIGSEGV, or SIGILL exception
type (see FLOAT.H for all these types).
This first parameter is the usual ANSI
signal type.
2. An integer pointer into the stack of the
interrupt handler that called the user-
specified handler.
This pointer points to a list of the
processor registers saved when the
exception occurred. The registers are in
the same order as the parameters to an
interrupt function:
BP, DI, SI, DS, ES, DX, CX, BX, AX, IP, CS, FLAGS
To have a register value changed when the
handler returns, change one of the locations
in this list.
For example, to have a new SI value on
return, do something like this:
*((int*)list_pointer + 2) = new_SI_value;
In this way, the handler can examine and make
any adjustments to the registers that you
want.
Return from Signal Handler
==========================
When the signal type is SIGFPE, SIGSEGV, or
SIGILL, a return from a signal handler is
generally not advisable because one of the
following has probably occurred:
* The results of an integer division are wrong.
* The state of the 8087 is corrupt.
* An operation that shouldn't have overflowed did.
* A bound instruction failed.
* An illegal operation was attempted.
These are the only times a return from a
signal handler is reasonable:
* The handler alters the registers so that
a reasonable return context exists, or
* The signal type indicates that the signal
was generated explicitly (for example,
FPE_EXPLICITGEN, SEGV_EXPLICITGEN, or
ILL_EXPLICITGEN).
Generally in this case you would print an
error message and terminate the program using
_exit, exit, or abort.
If a return is executed under any other
conditions, the program's action will
probably be unpredictable upon resuming.
See Also:
SIGFPE type signals
SIGSEGV type signals
SIGILL type signals