f5414d3f6c7d113a19189d9c03f1ed86dd7863bf
[mono.git] / mono / io-layer / handles.c
1 #include <config.h>
2 #include <glib.h>
3 #include <pthread.h>
4
5 #include "mono/io-layer/wapi.h"
6 #include "wapi-private.h"
7 #include "handles-private.h"
8
9 #include "mono-mutex.h"
10
11 #undef DEBUG
12
13 guint32 _wapi_handle_count_signalled(WaitQueueItem *item, WapiHandleType type)
14 {
15         guint32 i, ret=0;
16         
17         /* Count how many of the interesting thread handles are signalled */
18         for(i=0; i<item->handles[type]->len; i++) {
19                 WapiHandle *handle;
20
21                 handle=(WapiHandle *)g_ptr_array_index(item->handles[type], i);
22 #ifdef DEBUG
23                 g_message(G_GNUC_PRETTY_FUNCTION ": Checking handle %p",
24                           handle);
25 #endif
26                 
27                 if(handle->signalled==TRUE) {
28                         guint32 idx;
29                         
30 #ifdef DEBUG
31                         g_message(G_GNUC_PRETTY_FUNCTION
32                                   ": Handle %p signalled", handle);
33 #endif
34
35                         idx=g_array_index(item->waitindex[type], guint32, i);
36                         _wapi_handle_set_lowest(item, idx);
37                         
38                         ret++;
39                 }
40         }
41
42 #ifdef DEBUG
43         g_message(G_GNUC_PRETTY_FUNCTION ": %d signalled handles", ret);
44 #endif
45
46         return(ret);
47 }
48
49 void _wapi_handle_set_lowest(WaitQueueItem *item, guint32 idx)
50 {
51         mono_mutex_lock(&item->mutex);
52
53         if(item->lowest_signal>idx) {
54 #ifdef DEBUG
55                 g_message(G_GNUC_PRETTY_FUNCTION ": Set %p lowest index to %d",
56                           item, idx);
57 #endif
58         
59                 item->lowest_signal=idx;
60         }
61         
62         mono_mutex_unlock(&item->mutex);
63 }
64
65 /**
66  * CloseHandle:
67  * @handle: The handle to release
68  *
69  * Closes and invalidates @handle, releasing any resources it
70  * consumes.  When the last handle to a temporary or non-persistent
71  * object is closed, that object can be deleted.  Closing the same
72  * handle twice is an error.
73  *
74  * Return value: %TRUE on success, %FALSE otherwise.
75  */
76 gboolean CloseHandle(WapiHandle *handle)
77 {
78         g_return_val_if_fail(handle->ref>0, FALSE);
79         
80         handle->ref--;
81         if(handle->ref==0) {
82                 if(handle->ops->close!=NULL) {
83                         handle->ops->close(handle);
84                 }
85                 
86                 g_free(handle);         /* maybe this should be in
87                                          * ops, cuurently ops->close()
88                                          * is being used to free
89                                          * handle data
90                                          */
91         }
92         
93         return(TRUE);
94 }
95
96 /**
97  * SignalObjectAndWait:
98  * @signal: An object to signal
99  * @wait: An object to wait for
100  * @timeout: The maximum time in milliseconds to wait for
101  * @alertable: Specifies whether the function returnes when the system
102  * queues an I/O completion routine or an APC for the calling thread.
103  *
104  * Atomically signals @signal and waits for @wait to become signalled,
105  * or @timeout ms elapses.  If @timeout is zero, the object's state is
106  * tested and the function returns immediately.  If @timeout is
107  * %INFINITE, the function waits forever.
108  *
109  * @signal can be a semaphore, mutex or event object.
110  *
111  * If @alertable is %TRUE and the system queues an I/O completion
112  * routine or an APC for the calling thread, the function returns and
113  * the thread calls the completion routine or APC function.  If
114  * %FALSE, the function does not return, and the thread does not call
115  * the completion routine or APC function.  A completion routine is
116  * queued when the ReadFileEx() or WriteFileEx() function in which it
117  * was specified has completed.  The calling thread is the thread that
118  * initiated the read or write operation.  An APC is queued when
119  * QueueUserAPC() is called.  Currently completion routines and APC
120  * functions are not supported.
121  *
122  * Return value: %WAIT_ABANDONED - @wait is a mutex that was not
123  * released by the owning thread when it exited.  Ownershop of the
124  * mutex object is granted to the calling thread and the mutex is set
125  * to nonsignalled.  %WAIT_IO_COMPLETION - the wait was ended by one
126  * or more user-mode asynchronous procedure calls queued to the
127  * thread.  %WAIT_OBJECT_0 - The state of @wait is signalled.
128  * %WAIT_TIMEOUT - The @timeout interval elapsed and @wait's state is
129  * still not signalled.  %WAIT_FAILED - an error occurred.
130  */
131 guint32 SignalObjectAndWait(WapiHandle *signal, WapiHandle *wait,
132                             guint32 timeout, gboolean alertable)
133 {
134         gboolean waited;
135         guint32 ret;
136         
137         if(signal->ops->signal==NULL) {
138                 return(WAIT_FAILED);
139         }
140         
141         if(wait->ops->wait==NULL) {
142                 return(WAIT_FAILED);
143         }
144
145         waited=wait->ops->wait(wait, signal, timeout);
146         if(waited==TRUE) {
147                 /* Object signalled before timeout expired */
148 #ifdef DEBUG
149                 g_message(G_GNUC_PRETTY_FUNCTION ": Object %p signalled",
150                           wait);
151 #endif
152                 ret=WAIT_OBJECT_0;
153         } else {
154 #ifdef DEBUG
155                 g_message(G_GNUC_PRETTY_FUNCTION ": Object %p wait timed out",
156                           wait);
157 #endif
158                 ret=WAIT_TIMEOUT;
159         }
160
161         if(alertable==TRUE) {
162                 /* Deal with queued APC or IO completion routines */
163         }
164         
165         return(ret);
166 }