INtime SDK Help
iwin32 Architecture
INtime SDK v7.1 > About INtime > Alternate APIs > iwin32 API > iwin32 Architecture

Handles

Each object is identified by a handle. In INtime an object is uniquely identified by a single handle value (16 bits for INtime, 32 bits for NTX). This handle can be used in any INtime process and in Windows processes (using NTX). When the object is deleted with a type-specific deletion function such as DeleteRtSemaphore, the handle becomes invalid.

Iwin32 has a different handle system: the Create and Open functions return a handle and different callers may receive different handles for the same object. A handle is stored in 32 bits; an iwin32 handle can be distinguished from an INtime handle because its value is 0x10000 or greater. Every iwin32 object includes a handle count. When the last handle for an object is closed, the object is implicitly deleted.

In Windows, a handle is normally specific to a process and the same handle in different Windows processes may refer to different objects. Iwin32 implements a slightly different method, where all handle values are unique. This allows a handle to be shared between processes, which would be against the Win32 rules.

There is a limit on the number of objects that can exist at any time in the system, because INtime uses a table to define each object; the size of this table (GDT) is configurable up to a maximum of about 8000 entries. For information about GDT configuration, see Running the INtime Configuration Utility.

Each iwin32 object requires one, two (thread, timer, interrupt), or three (process) INtime objects. Additional handles for a given iwin32 object do not require additional INtime objects. Iwin32 uses a fixed size table for all handles, the size of which is configurable.

Named objects

Event, mutex, semaphore, and shared memory objects have a Create and an Open function. CreateXxx checks if the named object of that type already exists and, if so, returns an error and the found object's handle. If the name exists but belongs to another object type, the function fails. If the name does not occur yet, the object is created and the name remembered. If no name is supplied, the name check does not take place. OpenXxx does only the name check and if that fails, the whole operation fails.

All object types share one name space, which is not process specific but has system scope. Iwin32 allows names up to 128 characters.

There are no specific functions for named objects. For details see the functions listed in Events, Semaphores, and Shared memory.

Processes

A process is a container for objects and resources; it includes a virtual address space that is accessible only to the threads in the process. When a process is created, a primary thread is always created inside it (this is the function named main).

A process can refer to itself by a so-called pseudo handle, which is not a fixed value, but must be obtained by GetCurrentProcess. A pseudo handle can be used only by the process itself, and it cannot be closed (it implicitly closes when the process terminates).

A process can be explicitly terminated with the TerminateProcess or ExitProcess functions; implicit termination obeys these rules:

  1. When the primary thread returns, the process terminates.
  2. When the primary thread calls ExitThread explicitly, the process does not terminate.
  3. When any thread terminates and it was the last thread in the process, the process terminates.

Terminating a process does not necessarily delete the process! It only closes the pseudo handle for the process. Only when it is the last handle is the process deleted. When a process is terminated, all handles created by its threads are closed; again, this need not imply that all objects are deleted.

Waiting for a process to be signaled means waiting until the process has terminated.

Process functions include:

Threads

A thread is the active element type in the system. Each thread has a priority, a state, and a stack. The priority indicates the importance of the thread when it is in the ready state.

A thread is in one of these states:

A thread has a stack for calling functions and storing local variables and parameters. The stack must be big enough to contain all necessary data; when it overflows, it is not extended but the hardware exception EH_STACK_FAULT occurs.

A thread can refer to itself by a so-called pseudo handle, which is not a fixed value, but must be obtained by GetCurrentThread. A pseudo handle can be used only within the owning process, and it cannot be closed (it is implicitly closed when the thread terminates).

Waiting for a thread to be signaled means waiting until the thread has terminated.

Thread handling functions include:

Mutexes

A mutex is an object for getting exclusive access to a resource used by more than one thread, possibly in different processes.

When a thread attempts to get ownership of a mutex and that mutex is free, ownership is given to the owner; until the thread releases ownership, no other thread can own the same mutex. A thread can own the same mutex more than once, in which case it must release the mutex the same number of times.

When a thread with INtime priority Pw wishes to own a mutex and that mutex is already owned by another thread with priority Po, then if Pw < Po, the priority of the owning thread is changed to Pw until it releases all mutexes it owns. This avoids the infamous priority inversion.

Termination of a thread that owns one or more mutexes causes all threads waiting for such mutexes to be woken up with a WAIT_ABANDONED exception. Deleting a mutex causes all threads waiting for that mutex to be woken up with an ERROR_INVALID_HANDLE error code.

Mutex manipulation functions are:

Critical section (mutexes)

A critical section is a mutex that has no name; it can therefore only be used in the process that creates it. A critical section is identified by a CRITICAL_SECTION structure, which in turn contains the handle of the mutex. For more details see mutexes.

Critical sections are not available in the iwin32x API (but since mutexes are, they can be easily simulated).

Functions for critical sections include:

Semaphores

A semaphore is a counter that takes positive integer values called units. Threads release units to and wait for units from the semaphore. A semaphore can synchronize a thread's actions with other threads and can also be used to provide mutual exclusion for data or a resource (although a mutex may be better in that case).

A thread can release one or more units to a semaphore. Waiting can be done for a single unit only. A semaphore does not protect against priority inversion.

Deleting a semaphore causes all threads waiting for that semaphore to be woken up with an ERROR_INVALID_HANDLE error code.

Semaphore functions include:

Events

An event is a flag that can be set (signaled) or reset; it can be reset manually (once set, it remains set until explicitly reset by a ResetEvent call, independent of how many threads are woken up) or automatically (after waking up one thread, the event is reset).

Deleting an event causes all threads waiting for that event to be woken up with an ERROR_INVALID_HANDLE error code.

Event functions include:

Shared memory

Mutexes and semaphores allow threads to synchronize, but what if you want to exchange data? You can use INtime objects such as mailboxes, but in iwin32 you also find shared memory. Shared memory is memory that has been allocated by one process and that can be accessed by other processes as well. To access shared memory created by another process you need to know its name.

Since every process has its own virtual address space, a shared memory object must be mapped into a process' address space. Different processes may use different local addresses to access the same shared memory! The shared memory is only deleted when all its handles are closed.

Space for shared memory objects comes from an iwin32 virtual memory pool; the maximum size of that pool is configurable in the INtime Node Manager, advanced tab, iwin32 section, SegSize in multiples of 4 Mbytes.

It is up to the communicating threads to agree on a method of queuing data in the shared memory as necessary.

Shared memory functions include:

Timers

Any thread can be made to wait for a given time by using Sleep or RtSleepFt. A timer is simply a thread that gets woken up when its time passes. Creating a timer means that a thread is created that calls a user-provided function after a given time. This thread is a special one: it can not be suspended or resumed and its priority can not be changed. It should not call ExitThread and can not be terminated by TerminateThread.

Timer functions include:

I/O handling

In iwin32 a few general file handling functions are present. For many functions, the C-library offers alternatives. Device dependent functions (as provided by DeviceIoControl in Win32) can either be programmed using port I/O, or can be delegated to INtime device drivers.

In contrast to Win32, port I/O (accessing hardware ports directly) is allowed in all INtime threads.

I/O functions in iwin32 include:

Interrupt handling

Win32 does not provide interrupt handling functions, as this always takes place in the Windows kernel environment. Since interrupts are critical in INtime, we have extended iwin32 with interrupt handling. There are two choices for handling an interrupt:

When an interrupt comes from a PCI source, the actual interrupt line can be determined using RtGetBusDataByOffset. Access to I/O ports on the device for determining interrupt details is provided by the RtReadPortXxx and RtWritePortXxx functions.

The thread created for interrupt handling is a special one: it can not be suspended or resumed and its priority can not be changed. It should not call ExitThread and can not be terminated by TerminateThread.

Interrupt handling functions include:

Exception handling

Notes:   
  • Exception handling is part of the INtime API; for details, see Exception handling.
  • iwin32x does not have any Exception Handling calls, because Exception handling for Windows applications is provided by Microsoft Visual Studio and Windows.

Registry handling

This lists common operations on registry keys and the registry system calls that do the operations.

To . . . iwin32 call . . . iwin32x call . . .
Create a key RegCreateKeyEx Part of Win32
Delete a subkey from the registry RegDeleteKey Part of Win32
Delete a value from a registry key RegDeleteValue Part of Win32
Enumerate subkeys of an open registry key RegEnumKeyEx Part of Win32
Enumerate a value for an open registry key RegEnumValue Part of Win32
Establish a connection to a registry handle on another computer RegConnectRegistry Part of Win32
Open a key RegOpenKeyEx Part of Win32
Release a handle to a key RegCloseKey Part of Win32
Retrieve information about a registry key RegQueryInfoKey Part of Win32
Retrieve type and data for a value name associated with an open registry key RegQueryValueEx Part of Win32
Set the data and type of a value under a registry key RegSetValueEx Part of Win32
Write attributes of an open key into the registry RegFlushKey Part of Win32

Shutdown handling

There are two functions that allow attaching and releasing a handler for monitoring Windows shutdown.

To . . . iwin32 call . . . iwin32x call . . .
Attach a shutdown handler RtAttachShutdownHandler -
Release a shutdown handler RtReleaseShutdownHandler -
   
See Also