Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5760339
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: C/C++

2007-06-17 21:42:14

Introduction

This paper details how the NT based API WaitForMultipleObjects() was successfully ported to a Solaris operating environment. A thread-safe emulation based on the POSIX thread library and its basic synchronization primitives was used to accomplish this task.

Emulation of Win32 API WaitForMultipleObjects() Functionality Under The
Solaris Operating Environment

This project was undertaken to assist an ISV with the port of a server application from NT to Solaris, particularly the port of the WaitForMultipleObjects() API, which is not straightforward since there is no concept of events and handles in Solaris. Our implementation of this API is generic and can be applied to any handle type on NT. This paper discusses the design issues we faced and could be applicable to other developers facing similar port issues. The Appendix includes the source code for WaitforMultipleObjects API implementation and is POSIX compliant.

WaitFor

The WaitFor method is the basic thread synchronization mechanism for the NT operating system, and its successful implementation is critical to any NT emulation effort.

WaitFor allows NT threads to synchronize on the setting of one or more varieties of NT objects. The thread issuing a WaitFor is then blocked until either a timeout occurs after a pre-specified time, or when one or all of the objects it is waiting for gets "set".

The WaifFor is not blocking if one of the NT objects is already set when the WaifFor is first issued.

Back to Top


WaitForSingleObject

The WaitForSingleObject function takes a handle object as the first parameter and will not return before the object that is referenced by the handle attains the signaled state or the timeout value that is specified as the second parameter expires. This is simple.

WaitForMultipleObjects

The WaitForMultipleObjects call is similar, except that its main parameter (the second) is an array of Windows NT handle objects. The first parameter passed to it specifies the number of handles in this array. The third parameter is FALSE if waiting for ANY object is desired and TRUE if the function is to return only when all objects in the array have been set; the wait for ALL objects is desired.

Note that the handle array passed to WaitForMultipleObjects can be composed of an arbitrary mix of Windows NT handle objects. This includes thread handles, handles to processes, mutexes, semaphores, and events. Each handle type is a subclass of the base handle class.

A thread can wait for multiple objects to be set in one of two ways:

1. ALL

The issuing thread will unblock after ALL objects specified in the call have been set. This is fairly simple to emulate. Each object is waited for in turn until all have been set or until timeout occurs. At that point this function returns.

2. ANY

The issuing thread will unblock after ANY one specified object in the call has been set.

WaitForMultipleObjects for the case ANY is the most difficult of all Win32 routines to emulate since UNIX® (thus Solaris) does not support anything like it. The problem is that the issuing thread has to actually be blocked on a single Solaris variable, yet the setting of any one of a series of NT objects has to result in the signaling of that variable.

Following is a list of requirements for the solution:

  1. More than one thread could be waiting at any one time on the same handle.
  2. Spurious signals may not be sent to threads.
    Note: For example, if thread 1 is waiting on two handles, A and B, and thread 2 is waiting on two handles A and C, and handle B is set, a signal may not be sent to thread 2 just because it is waiting on handle A common to threads 1 and 2.
  3. No polling.

The solution detailed in this paper makes use of the subscription model, that is, the interested thread subscribes itself to the interested wait object and goes to sleep until signaled.

The handle is a composite object containing a list of mutex_cond objects. Each mutex_cond object contains a condition variable and a mutex.

Back to Top


The handle structure will look like this:

Handle{
List mutex_cond;
Boolean is_signaled;

}

mutex_cond{
Mutex mutex;
Cond_var cond_var;
}

Instead of having two lists, one of mutex and the other of cond_var, the mutex_cond object is created so that the action of adding the pair of mutex and condition variables to the handle is atomic.

The model proposes that each thread that issues or executes on a WaitFor call on any one or more handles subscribes itself to those handles by adding a pair of mutex/cond_var to that handle list and then waits on that mutex/cond_var pair. When a handle is set, all threads waiting on that handle are signaled. Thus, if two threads wait on a handle, there will be two elements in the list of that handle. And when the handle is set, both of the threads are signaled.

ALL or logical AND

In the case of ALL or logical AND, the thread needs to wait for all handles to be set, or for timeout, before exiting from the WaitFor call. One mutex_cond object containing a condition variable and a mutex is created for every handle and added to that handle's list.

Back to Top


The code will look like this:

Boolean WaitForMultipleObjects(int Count, void 
**Handle, boolean fWaitall, long msTimeOut)
{
mutex_cond_t mutex_cond[Count];

for(i=0; i < COUNT; I++){
INITIALIZE THE MUTEX AND CONDITION VARIABLE
CREATE A NEW MUTEX_COND OBJECT MUTEX_COND[I]
ADD THE MUTEX_COND OBJECT TO THE LIST OF THE
HANDLE[I]
}

FOR(I=0; I < COUNT; I++){
LOCK MUTEX_COND[I]->mutex
while (! Handle[i]->is_signaled) {
Wait until timeout on mutex_cond[i]->cond_var
}
UnLock mutex_cond[i]->mutex
}

for(i=0; i < COUNT; I++){
DELETE MUTEX_COND[I] FROM HANDLE LIST
}
}

ANY or logical OR

In the case of ANY or logical OR, the preceding example illustrates that instead of the thread creating a new mutex_cond object for each handle, there is a single common mutex_cond object for all the handles specified, and the thread wait on this common mutex_cond object for all the handles. In other words, the thread subscribes to each handle with the common mutex_cond object, and waits on it. So, if any handle gets set, the thread returns from the WaitFor method as expected. This prevents the need for any kind of polling, which can be highly CPU intensive.

Back to Top


The code will look like this:

Boolean WaitForMultipleObjects(int Count, 
void **Handle,
boolean fWaitall, long TimeOut)
{
Create one common mutex_cond object:
common_mutex_cond
Initialize the mutex and condition variable

for(i=0; i < COUNT; I++){
ADD THE COMMON_MUTEX_COND OBJECT TO THE LIST OF THE
HANDLE[I]
}

LOCK COMMON_MUTEX_COND->mutex

for(i=0; i < COUNT; I++){
CHECK FOR EACH HANDLE IF IT HAS BEEN SET, IF
SET EXIT
}

IF (NONE OF THE HANDLES HAVE BEEN SET) {
WAIT UNTIL TIMEOUT ON COMMON_MUTEX_COND->cond_var,
common_mutex_cond->mutex
}

UnLock common_mutex_cond->mutex

for(i=0; i < COUNT; I++){
DELETE COMMON_MUTEX_COND ELEMENT FROM LIST OF
HANDLE[I]
}
}

Back to Top


SIGNALING

When a handle is set, a signal is sent to all threads waiting on that handle.

void HandleSet(void *Handle ){
Iterate through the Handle List {
Lock Handle->List_element->mutex
}

Iterate through the Handle List {
Signal Handle->List_element->cond_var
}

Iterate through the Handle List {
Unlock Handle->List_element->mutex
}
}

The complete code for the case of an event handle and a test driver is available in the Appendix. The design is generic and this code can be modified to use a mix of one or more handle types. The code uses the POSIX thread library.

The same subscription model can be used for the case of WaitForSingleObject if the Count parameter in the case of WaitForMultipleObjects is set to 1.

For example:

Boolean WaitForSingleObjects(void **Handle, long 
msTimeOut)
{
WaitForMultipleObjects(1, **Handle, AND,
msTimeOut);
}

Back to Top


LIMITATION

  1. Synchronized objects states are not modified. In other words, they are not non-signaled.
  2. Named handles require the handles to reside in shared space, and could be acted upon by other processes. This requires that the mutex and condition variables be created with system scope (the threads are already created with system scope). The shared space could be mmaped on startup and shared by different processes.
  3. Handles can be closed multiple times and need to be freed when the reference count goes to zero.
  4. There is no check for duplicate handles.
  5. Handle type is not checked.

CONCLUSIONS

The port of WaitForMultipleObjects() Win32 API has been successfully done and can be used by other groups for porting Win32 applications from NT to the Solaris operating environment. Much more than that, this implementation of the handle structure forms the basic building block, making use of the Solaris synchronization variables, on top of which complex synchronization objects can be built.

REFERENCES

  1. Kleinman, R. (1995) Emulation of Server-side Win32 Functionality under Solaris.
  2. Ruediger R. Asche (1994) Compound Win32 Synchronization Objects

文件:source.tar
大小:15KB
下载:下载
阅读(1829) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~