home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
api.zip
/
API.INF
(
.txt
)
next >
Wrap
OS/2 Help File
|
1994-04-20
|
13KB
|
280 lines
ΓòÉΓòÉΓòÉ 1. Introduction ΓòÉΓòÉΓòÉ
Because the C Set/2 and C Set++ runtime libraries must use the operating APIs
to perForm their work, there is a short list of these APIs that can cause the
runtime library to behave in unexpected ways.
This document will list the APIs that are known to cause problems, and how they
can be used safely.
ΓòÉΓòÉΓòÉ 2. APIs you should never use ΓòÉΓòÉΓòÉ
This section describes OS/2 APIs that can cause severe problems with C/C++
applications.
ΓòÉΓòÉΓòÉ 2.1. DosKillThread() ΓòÉΓòÉΓòÉ
In all cases, this API works by sending an OS/2 exception to the thread being
killed. It is usually not desirable to kill a thread at an arbitrary point.
Think of a thread updating a linked list in a multithreaded program.
1. It probably owns a semaphore to protect the list, so that only one thread
can modify it at a time
2. It probably breaks the linkages at some point in its processing to add or
remove an element from the list.
When the exception occurs, the thread terminates unless the exception is
somehow deferred or handled. This may have the following unfortunate
consequences:
1. The semaphore is left in the "OWNER DIED" state. The only way to recover
from this is to destroy the semaphore and recreate it. Messy at best...
2. The linked list may be left in a broken state.
The problem is compounded by the fact that you, in general, do not know what
the thread is doing when you kill it. That means that you often have no idea
what killing it has damaged, or how to repair it! That's a recipe for disaster!
This API is particularly dangerous if the thread could have been executing code
over which you have no control (like the C/C++ runtime code, or an OS API).
You must assume that this code cannot tolerate having its thread of execution
killed.
The limitations on this API depend on which version of OS/2 you are running.
ΓòÉΓòÉΓòÉ 2.1.1. DosKillThread on OS/2 2.0 and 2.1 ΓòÉΓòÉΓòÉ
To put it bluntly, never use this API on this operating system. There are no
circumstances where this API is safe to use with C Set/2 or C Set++. The API
works by sending the synchronous process termination exception
(XCPT_PROCESS_TERMINATE) to the thread being killed. There is no way for the
target thread to defer or ignore the exception. It must handle it and then
terminate.
In most cases, protecting a thread so that it can be killed is not possible.
The problem is essentially the same as writing code that can survive a
protection violation; a usually impossible task.
1. If your code makes any calls to any functions that you do not completely
control, you must assume that calling DosKillThread() is unsafe. This
includes OS/2 APIs, C/C++ runtime functions (other than inlined functions),
database calls, and so on. This includes C++ constructs that become
runtime functions, like new and delete.
2. Assuming that you can satisfy the first point, you will need to write an
OS/2 exception handler to intercept the XCPT_PROCESS_TERMINATE exception,
which will then 'throw' a C++ exception. You will need to 'catch' and
"re-throw' the exception at every point in your code that needs to be
cleaned up.
Note: Do not assume that you can test code using this API. Due to the fact
that OS/2 uses a pre-emptive multitasking algorithm, the timing of thread swaps
is, effectively, indeterminate. This means that test runs are not repeatable,
and that reliable testing is not possible. You must "prove" your code correct
by a formal inspection process.
ΓòÉΓòÉΓòÉ 2.1.2. DosKillThread on OS/2 2.11 ΓòÉΓòÉΓòÉ
Unlike the situation on OS/2 2.0 and 2.1, on this version of the operating
system, this API is now merely difficult to use safely. It cannot be used
unless the thread being killed has been designed to allow it. On this version
of OS/2 the API works by sending the asynchronous process termination exception
(XCPT_ASYNC_PROCESS_TERMINATE) to the thread being killed. Unlike the
synchronous termination exception, this exception can be either deferred or
ignored.
The C Set/2 and C Set++ runtime libraries protect themselves against this
problem by deferring the exception until the runtime library call has returned
to user code. This has one side effect: you cannot kill a thread that is
waiting on keyboard input (sorry about that, but not doing so causes some
really nasty intermittent problems with the runtime library).
You can protect your own code in three ways:
1. You can put your code into a "must complete" section, by using the
DosEnterMustComplete() and DosExitMustComplete() APIs. See the cautions
regarding them in this document. The thread terminates after you exit the
topmost must complete section.
2. You can write an OS/2 exception handler to simply ignore the exception. A
bit drastic!
3. You can write an OS/2 exception handler to catch the exception, put a "mark
on the wall", and then ignore the exception. At an appropriate point in
your code, you check for the "mark on the wall", and if it's there,
terminate the thread.
Of the three, the last has the best performance, and the first is the easiest.
Note: Do not assume that you can test code using this API. Due to the fact
that OS/2 uses a pre-emptive multitasking algorithm, the timing of thread swaps
is, effectively, indeterminate. This means that test runs are not repeatable,
and that reliable testing is not possible. You must "prove" your code correct
by a formal inspection process.
ΓòÉΓòÉΓòÉ 2.2. DosUnwindException() ΓòÉΓòÉΓòÉ
This API can remove the C and C++ OS/2 exception handlers from the stack,
causing C signal handlers or C++ exception handling to malfunction. It also
requires knowledge of the machine state, which is not available in either of
these languages.
You are recommended to use longjmp() instead. longjmp() will unwind OS/2
exception handlers from the stack, preventing any problems with them.
ΓòÉΓòÉΓòÉ 2.3. DosAcknowledgeSignalException() ΓòÉΓòÉΓòÉ
Use of this function is recommended only from within a user written OS/2
exception handler. It is not required unless you wish to unblock the OS/2
signal exceptions without leaving an OS/2 exception handler. OS/2 Signal
exceptions are automatically acknowledged if the OS/2 exception handler returns
XCPT_CONTINUE_EXECUTION.
Using this API inside a C signal handler may cause the C/C++ handling of OS/2
signal exceptions to fail, as this depends on the library controlling when OS/2
signal exceptions are acknowledged.. The library OS/2 exception handler will
take care of acknowledging signals for you.
ΓòÉΓòÉΓòÉ 3. APIs that may be used with caution ΓòÉΓòÉΓòÉ
This section describes OS/2 APIs that can be used in C/C++ applications as long
as appropriate precautions are taken.
ΓòÉΓòÉΓòÉ 3.1. DosSuspendThread() ΓòÉΓòÉΓòÉ
This API can cause a thread to stop at an arbitrary point. Since, in most
useful multithreaded programs, a suspended thread is likely to own a mutex
semaphore, you are exposed to a deadlock. The only safe way to use this API is
to call DosResumeThread() as soon as possible, and to avoid making any calls to
any C/C++ runtime routine while a thread is suspended. This API is of limited
use, and can often be replaced with an OS/2 semaphore.
ΓòÉΓòÉΓòÉ 3.2. DosEnterCritSec(): ΓòÉΓòÉΓòÉ
This API prevents thread switching within your process. It is equivalent to
calling DosSuspendThread() for every thread in your process except the current
thread. For each call to DosEnterCritSec(), you must call DosExitCritSec().
Keep critical sections short, and do not put calls to OS/2 APIs or C/C++
library routines inside them.
Where possible (and it usually is), use an OS/2 mutex semaphore rather than
this API.
ΓòÉΓòÉΓòÉ 3.3. DosExit() ΓòÉΓòÉΓòÉ
Unless you are using the subsystems programming library (the /Rn compile
option), this API is not supported in conjunction with C Set++ applications.
DosExit prevents the runtime library from cleaning up, and inhibits running the
atexit() and onexit() routines. If used in place of _endthread(), it can cause
a subsequently started thread to start up with invalid default values (see
DosCreateThread()).
Use exit(), abort(), _endthread(), or fall out the bottom of main(). These do
much the same thing, and they're portable too!
ΓòÉΓòÉΓòÉ 3.4. DosSetSignalExceptionFocus() ΓòÉΓòÉΓòÉ
This API is fully supported under the susbsystems programming library (the /Rn
compile option).
With the single and multitasking libraries, you are exposed to changing the
behavious of the C signal handling behaviour. C++ applications assume that
they have the focus for signal exceptions. Removing the focus will prevent you
from getting SIGINT and SIGBREAK signals from the keyboard. This is not a
problem is you do not intercept these signals.
DosCreateThread()
This API is the only way to start a new thread if you are using the subsystems
programming libraries (compile option /Rn), and its use is supported under that
set of circumstances.
This API is not supported for use with the singly threaded libraries (compile
option /Gm-), as these libraries lack the internal controls to allow multiple
threads to use the library.
DosCreateThread() is supported for use with the multithreaded libraries
(compile option /Gm+) as long as the following code is also used:
1. The function in the new thread must register the C/C++ OS/2 exception
handler.
2. The new thread must call _fpreset() before doing any floating point
operations
3. The new thread must never end by falling out of the bottom of the function.
It must call _endthread().
An example of this would be:
/* register the C/C++ exception handler */
#pragma handler(threadfn)
void threadfn(ULONG arg) {
_fpreset(); /* reset the 80386 exception handler */
.
.
.
_endthread(); /* exit with _endthread() so the library */
/* data areas are cleaned up */
}
ΓòÉΓòÉΓòÉ 3.5. DosEnterMustComplete(): ΓòÉΓòÉΓòÉ
This API is used to hold off all asynchronous exceptions, including
XCPT_ASYNC_PROCESS_TERMINATE. You must call DosExitMustComplete() to reenable
asynchronous exceptions. Since terminating a multithreaded process causes an
asynchrnous process termination exception (XCPT_ASYNC_PROCESS_TERMINATE) on
each thread, multithreaded processes cannot end if any thread is in a must
complete section.
ΓòÉΓòÉΓòÉ 3.6. DosSetExceptionHandler() ΓòÉΓòÉΓòÉ
This API is supported for use with the subsystems programming library, although
it is assumed that you understand how OS/2 exceptions work.
When used with the standard libraries (single or multithreaded), this API will
override the runtime library excpetion handling. You should handle only those
exception you specifically expect, and pass all others on. If you intercept the
OS/2 exceptions, you may inhibit the calling of previosly registered signal
handlers. See the companion EXCEPT.INF file for a full treatment of the
subject.
ΓòÉΓòÉΓòÉ 3.7. DosScanEnv() ΓòÉΓòÉΓòÉ
This API is supported for use with the subsystems programming library as the
only way to get the OS/2 environment data.
Its behaviour with the standard libraries (single or multithreaded), is not
exactly the same as the getenv() library function. The DosScanEnv() API will
give you values that were in the environment when the process started. The
getenv() library function will give you those values, as modified by any
intervening _putenv() calls.
ΓòÉΓòÉΓòÉ 3.8. OS/2 File I/O APIs ΓòÉΓòÉΓòÉ
These APIs are equivalent to the low level I/O functions in IO.H. They may be
freely intermixed with those calls, as the low level I/O handles are also OS/2
file handles.
Intermixing C/C++ stream I/O with either OS/2 File I/O APIs or the C/C++ low
level I/O functions should be avoided. Use either one or the other on any
file, as both have the implicit assumption that they "own the file".