[Next] [Previous] | Chapter 3 |
A process is a collection of threads and resources that are owned by those threads. Each process occupies a unique address space in memory that cannot be accessed by other processes in the system. Two processes can access the same area in memory only by using shared memory. A process also contains file handles, semaphores, and other resources. All processes contain at least one thread, the main thread. A process also contains a unique identifier-a PID. A process contains its own set of memory pages that can be swapped in and out as the kernel switches from one process to the other. A process can create other processes; however, these must be of the same session type. For instance, a full-screen process can only create other full-screen processes. The live types of processes are OS/2 Full Screen, OS/2 windowed, DOS Full Screen,.DOS windowed, and Presentation Manager.
A session is similar to a process except a session also contains ownership
of the mouse, keyboard, and video. A session can contain either one process
or multiple processes. The task list (accessed by Ctrl-Esc) contains a
list of all running sessions. When a process or session creases a new session
using DosStartSession, the keyboard, screen, and mouse are
responsive only to the session in the foreground.
The session chosen as the background can gain control of the three
resources only by switching to the foreground.
![]() |
The OS/2 Scheduler runs on a round-robin type of disbursement of CPU time. The Scheduler deals only with threads, not processes or sessions. Threads have four different priority levels: time-critical, server class or fixed high, regular, and idle time. The first threads to run are the time-critical threads. All time-critical threads will run until there are no more time-critical threads waiting to be run. After all time-critical threads are finished, the server-class threads are run. After server-class, the regular class of threads are run. After the regular class of threads are run, idle-time threads are run. Within each class of priorities are 32 sublevels. A thread that is not running is called a "blocked" thread. |
The time slices for threads that are given a starvation boost or an
I/O boost are different from a normal time slice. Because of she tinkering
the scheduler does with their priorities, they do not get to run as long
as a nonadjusted thread would run. The length of time for the "short" and
normal time slices is controlled by the TIMESLICE parameter in CONFIG.SYS.
The first value represents the "shots" time slice length; the default amount
of time is set to 32 ms. The second value represents the normal time slice
length; the default amount of time is set to 65536 ms.
A programmer can refine the way the threads in a program are run in
four ways:
APIRET APIENTRY DosSetPriority(
ULONG scope,
ULONG ulClass,
LONG delta,
ULONG PorTid);
DosSetPriority has four parameters. The first
indicates to what extent the priority is to be changed. The priority can
be changed at the process or thread level. The ulClass parameter
indicates at what class to set the priority. The delta parameter indicates
at what level within the class to set the priority. The last parameter
is the process ID of the process to be affected .A value of 0 indicates
the current process. Note that a process can change just the priority of
a child process. DosSetPriority can be called anytime
in the threads lifetime. It is used to adjust the class and/or the priority
level within that class.
DosSetPriority should be used to
adjust threads whose tasks need special timing considerations. For instance,
a thread handling communications would probably want to run at a server
class. A thread that backs up files in the background should be set at
idletime priority, so that it would run when no other tasks were running.
You can change the priority of threads in another process. but only if
they were not changed explicitly from the regular class.
APIRET DosResumeThread(TID tid);The only parameter to each of these functions is the thread ID of the thread. DosResumeThread and DosSuspendThread are used to change a thread's locked stare. DosSuspendThread will cause a thread to be set to a blocked state. DosResumeThread is used to cause a suspended thread to be put back in the list of ready-to-run threads.
APIRET DosSuspendThread(TID tid);
![]() |
Gotcha!
DosEnterCritSec can be a very dangerous function.
If for any reason the single thread running is put in a blocked
state and needs some other thread to cause it to be unblocked, your program
will go out to lunch and will not return. For example. DosWait...Sem are
major no-nos in a critical section, because the required DosPost...Sem
calls probably will exist in a thread that will be put in a suspended slate.
|
DosSleep is the most practical function of the group.
Using this function you can put a thread in a suspended state until a specified
amount of time has passed. DosSleep has only one argument,
the amount of time to "sleep". This value is specified in milliseconds.
A thread cannot suspend other threads using DosSleep, only
itself. When DosSleep is called with an argument of
0, the thread gives up the rest of its time slice. This does not change
the thread's priorities or affect its position in the list of ready-to-run
threads.
DosCreateThread (&tidThread,
/* thread TID */
pfnThreadFunction, /* pointer to fn */
ulThreadParameter, /* parameter passed */
ulThreadState, /* 0 to run, 1 to suspend */
ulStackSize ); /* 4096 at a minimum */
The first parameter contains the address of the threads TID, or Thread
ID. The next parameter is .a pointer to the function that the operating
system will call when the thread is running.. When using
DosCreateThread , a typical function prototype of a thread function
looks something like this:
VOID APIENTRY fnThread( ULONG ulThreadArgs)
Notice the APIENTRY keyword. This is used to indicate that this is a function that will be called by the operating system. The ulThreadArgs is 4 bytes of data, in the form of a ULONG, that are passed as an argument to the thread function. If you need to pass more than one value, you need to create a structure that contains all the values you want to pass. The first bytes of the structure should contain the size of the structure that is being passed. Also, if you use a structure, make sure you pass the address of the structure as the data. The ulThreadState parameter indicates whether the thread is started in a running state (with a value of 0) or in a suspended stare (with a value of 1). If the thread is started suspended, somebody needs to call DosResumeThread to get the thread going. The last parameter is the stack size. The threads stack is located in memory when the thread is blocked and is loaded into registers when the thread becomes ready to run. In OS/2 2.0, the programmer no longer needs to mess with allocating and freeing the memory for the stack. However, the programmer does need to know the maximum amount of memory that the stack will use. This is the value passed as the last parameter. This memory is not committed until it is absolutely necessary. The thread stack uses guard pages to commit a new page as necessary. Also, you may notice that a thread stack grows downward rather than upward as normal memory grows.
_beginthread ( pfnThreadFunction,
/* void pointer
to thread function */
pNull,
/* this is NOP parameter,
used for migration */
ulStackSize, /* stack size */
pArgList); /* pointer to argument list */
The prototype for a thread function changes a little here. The typical
thread function prototype looks something like this:
void fnThread( void *pArgList);
![]() |
Gotcha!
When using the C Set/++ compiler, make sure you specify the multithreaded
option, Gm+. Also, either let the compiler link in the proper library for
you, or make sure you specify DDE4M*.LIB
|
THREADS.CThe first part of the program is the actual creation of the threads. We'll create five almost identical threads. Each thread is started in suspended state by specifying 1 (THREAD_SUSPEND) as ulThreadFlags. The thread function, MyThread, is assigned to pfnThreadFuncrion. Since the thread function itself is fairly small, the minimum stack size of 4.096 is specified.
THREADS.MAK
THREADS.DEF
The one difference between the five threats is their priority. Each
thread priority is passed to MyThread in the ulThreadArgsr variable. An
array,ulThreadPrioriries[], holds all the possible thread priority classes.
DosSetPriority is used actually to change the priority
of the threads from regular priority to the respective priority in the
ulThreadPrioriries[] array. The first parameter, PRTY_THREAD, specifics
that only one thread, not all the threads in the process, will have its
priority affected. The second parameter is the priority class to use. The
third parameter is the delta of the priority level. Within each class ate
32 levels that can be used to refine a thread's priority even further.
Threads at level 31 of a class will execute before threads at level 0 of
the same class. This parameter, specifies the change to make to the current
level, not the absolute level value itself. Values are from -31
to +31. A value of 0 indicates no change, and this is what we use in this
example. The last parameter, tidThreadID[], is the thread ID of the thread
whose priority is to be changed.
Once the thread is created and its priority has been changed, DosResumeThread
is called to wake the thread up and have it begin running.
These steps are repeated for all five threads in a FOR loop. DosSleep
is used to delay the main thread from ending for 2 seconds. This gives
all the threads a chance to complete.
PROG.CThe first parameter or DosExecPgm is a buffer that is used to store information if the application being started fails. The size of the buffer is the next parameter.
PROG.MAK
PROG.DEF
![]() |
Gotcha!
The parameter string conforms to regular C parameter conventions, where argv[0] is the name of the executing program. After the program name, you must insert one null character. Following the null is the regular string of program arguments. These arguments must be terminated by two null characters. This is accomplished easily by manually inserting one null as the end of the argument string and letting the normal C string null termination insert the other.
|
The argument string for this example is:
"CMD.EXE\0 /C dir *.*\0"
CMD.EXE will execute a new command processor session. The "\0" is the first null character. The argument string "/C dir *.*\0" indicates the session will be cloned when it finishes executing the dir *.* command. The "\0" at the end is the first of the last two nulls. The second null is inserted automatically at the end of the string.
The fifth parameter is the environment string to pass to the new program.
This is formatted:
variable = text \0 variable = text \0\0
Each environment variable you want to set must be ended with a null character. The end of the string must be terminated with two null characters. A null value in the environment string variable indicates that the child process will inherit its parent's environment.
The next parameter is a RESULTCODES structure. This structure contains
two values, a termination code and a result code. The operating system
provides a termination code to indicate whether the program ended normally
or whether some error, for example, a trap, ended the program abruptly.
The result code is what is returned by the program itself, either through
DosExitProcess or through return.
The last parameter is the actual name of the program to be executed.
A fully qualified pathname is necessary only if the executable file is
not found in the current directory or in any of the directories specified
in the path.
There are several ways to tell whether a child process has terminated,
but the easiest by far is DosCwait. This function either will wait indefinitely
until a child process has ended, or will return immediately with an error,
ERROR_CHILD_NOT_COMPLETE.
All are started the same way, using DosStartSession.
![]() |
Gotcha!
There is a little bit of a trick to determine whether to use DosExecPgm or DosStartSession. The difference lies in whether she newly created process is going to perform any input or output. Table 3.1 outlines the guidelines. If you need to determine the type of an application (or .DLL). DosQueryAppType can be used. |
Parent Type | Child Type | Child does I/O ? | Use |
PM | PM | - | DosExecPgm or DosStartSession |
Non-PM | PM | - | DosStartSession |
PM | Non-PM | yes | DosStartSession |
PM | Non-PM | no | DosExecPgm or DosStartSession |
The following example program starts a seamless Windows session using DosStartSession
STARTWIN.CThe DosStartSession function itself is actually very small. Most of the preparatory work is done by setting up the STARTDATA structure. The structure looks like this:
STARTWIN.MAK
STARTWIN.DEF
Start session data structure.
typedef struct _STARTDATA
{
USHORT
Length; /* The length of the data structure, in bytes,
including Length itself. */
USHORT
Related; /* An indicator which specifies whether the session
created is related to the calling session. */
USHORT
FgBg;
/* An indicator which specifies whether
the new session should be started in the foreground or background. */
USHORT
TraceOpt; /* An indicator which specifies whether the program
started in the new session should be executed under conditions for tracing.
*/
PSZ
PgmTitle;
/* Address of an ASCIIZ string that contains the
program title. */
PSZ
PgmName;
/* The address of an ASCIIZ string that contains
the file specification of the program to be loaded. */
PBYTE
PgmInputs;/* Either 0 or the address
of an ASCIIZ string that contains the input arguments to be passed to the
program. */
PBYTE
TermQ;
/* Either
0 or the address of an ASCIIZ string that contains the file specification
of a system queue. */
PBYTE
Environment;/* The address of an environment string to be
passed to the program started in the new session. */
USHORT
InheritOpt; /* Specifies whether the program started in the
new session should inherit the calling program's environment and open file
handles. */
USHORT
SessionType;/* The type of session that should be created
for this program. */
PSZ
IconFile;
/* Either 0 or the address of an ASCIIZ
string that contains the file specification of an icon definition. */
ULONG
PgmHandle; /* Either 0 or the program handle. */
USHORT
PgmControl;/* An indicator which specifies the initial state
for a windowed application. */
USHORT
InitXPos; /* The initial x-coordinate, in pels, for
the initial session window. */
USHORT
InitYPos; /* The initial y-coordinate, in pels, for
the initial session window. */
USHORT
InitXSize; /* The initial x extent, in pels, for the
initial session window. */
USHORT
InitYSize; /* The initial y extent, in pels, for the initial
session window. */
USHORT
Reserved; /* Reserved; must be zero. */
PSZ
ObjectBuffer;
/* Buffer in which the name of the object that
contributed to the failure of DosExecPgm is returned. */
ULONG
ObjectBuffLen;/* The length, in bytes, of the buffer pointed
to by ObjectBuffer. */
} STARTDATA;
typedef STARTDATA *PSTARTDATA;
Length is the length of the structure in bytes.
FgBg specifies whether the new session will be
a child session (field is TRUE) or nit independent session (field is FALSE).
FgSg defines whether the session is to be sinned
in the foreground (field is FALSE) or in the background (field is TRUE).
TraceOpt specifies whether there is to be
any debugging (tracing) of the new session. TRUE indicates debug on; FALSE
indicates debug off.
PgmTitle is the name that the program is to be
called. This is not the name of the executable, only the title for any
windows or task list. If a NULL is used, the executable name is used for
the title.
PgmName is the fully qualified pathname of the
program to load.
PgmInputs is a pointer to a string of program arguments
(see page 23 for argument formatting.)
TermQ is a pointer to a string that specifies the
name of a system queue that will be notified when the session terminates.
Environment is a pointer to a string of environment
variables (see page 2.3 for environment variable formatting.)
InherritOpt indicates whether the new session
will inherit open file handles and an environment from the calling process.
TRUE in this field will cause the session to inherit the patent's environment;
FALSE will cause the session to inherit the shell's environment.
SessionType specifies the type of session to start.
Possible values are listed in Table 3.2
Value | Description |
SSF_TYPE_DEFAULT | Uses the program's type as the session type |
SSF_TYPE_FULLSCREAN | OS/2 full screen |
SSF_TYPE_WINDOWABLEVIO | OS/2 window |
SSF_TYPE_PM | Presentation Manager program |
SSF_TYPE_VDM | DOS full screen |
SSF_TYPE_WINDOWEDVDM | DOS window |
In addition. Table 3.3 lists the values that are also valid for Windows
programs.
Value | Description |
PROG_31_STDSEAMLESSVDM | Windows 3.1 program that will execute in its own windowed |
PROG_31_STDSEAMLESSCOMMON | Windows 3.1 program that will execute windowed session. |
PROG_31_ENHSEAMLESSVDM | Windows 3.1 program that will execute in enhanced compatibility mode in its own windowed session. |
PROG_31_ENHSEAMLESSCOMMON | Windows 3.1 program that will execute in enhanced compatibility mode in a common windowed session |
PROG_31_ENH | Windows 3.1 program that will execute in enhanced compatibility mode in a full screen session. |
PROG_31_STD | Windows 3.1 program that will execute in a full screen session. |
IconFile is a pointer to a fully qualified pathname
of an .ICO file to associate with the new session.
PgmName i s a program handle that Is returned from either WinAddProgram
or WinQueryProrgamHandle A 0 can be used if these functions are not used.
PgmControl specifies the initial attributes
for either the OS/2 window or DOS window sessions. The following values
can be used:
SSF_CONTROL_VISIBLEExcept for SSF_CONTROL_NOAUTOCLOSE and SSF_CONTROLSETPOS, the values are pretty self-explanatory. SSF_CONTROL_NOOAUTOCLOSE is used only for the OS/2 windowed sessions and will keep the sessions open after the program has completed. The SSF_CONTROL_SETPOS value indicates that the operating system will use the InitXPos, InitYPos, InitXSise. and InitYSize for the size and placement of the windowed sessions.
SSF_CONTROL_INVISIBLE
SSF_CONTROL_MAXIMIZE
SSF_CONTROL_MINIMIZE
SSF_CONTROL_NOAUTOCLOSE
5SF_CONTROL_SETPOS
The second parameter to DosStartSession is the address of a ULONG
that will contain the session ID after the function has completed. The
last parameter is the address of a PID (process ID) that will contain the
new process's PID after the session has started.
[Next] [Previous] | Chapter 3 |