- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / scheduler / k32obj.c
1 /*
2  * KERNEL32 objects
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include "winerror.h"
9 #include "k32obj.h"
10 #include "heap.h"
11 #include "process.h"
12 #include "server.h"
13
14
15 /* The declarations are here to avoid including a lot of unnecessary files */
16 extern const K32OBJ_OPS PROCESS_Ops;
17 extern const K32OBJ_OPS THREAD_Ops;
18 extern const K32OBJ_OPS MEM_MAPPED_FILE_Ops;
19
20 static const K32OBJ_OPS K32OBJ_NullOps =
21 {
22     NULL     /* destroy */
23 };
24
25 static void K32OBJ_Destroy( K32OBJ *obj );
26
27 static const K32OBJ_OPS K32OBJ_DefaultOps =
28 {
29     K32OBJ_Destroy     /* destroy */
30 };
31
32
33 const K32OBJ_OPS * const K32OBJ_Ops[K32OBJ_NBOBJECTS] =
34 {
35     NULL,
36     &K32OBJ_DefaultOps,     /* K32OBJ_SEMAPHORE */
37     &K32OBJ_DefaultOps,     /* K32OBJ_EVENT */
38     &K32OBJ_DefaultOps,     /* K32OBJ_MUTEX */
39     &K32OBJ_NullOps,        /* K32OBJ_CRITICAL_SECTION */
40     &PROCESS_Ops,           /* K32OBJ_PROCESS */
41     &THREAD_Ops,            /* K32OBJ_THREAD */
42     &K32OBJ_DefaultOps,     /* K32OBJ_FILE */
43     &K32OBJ_DefaultOps,     /* K32OBJ_CHANGE */
44     &K32OBJ_DefaultOps,     /* K32OBJ_CONSOLE */
45     &K32OBJ_NullOps,        /* K32OBJ_SCREEN_BUFFER */
46     &MEM_MAPPED_FILE_Ops,   /* K32OBJ_MEM_MAPPED_FILE */
47     &K32OBJ_NullOps,        /* K32OBJ_SERIAL */
48     &K32OBJ_NullOps,        /* K32OBJ_DEVICE_IOCTL */
49     &K32OBJ_DefaultOps,     /* K32OBJ_PIPE */
50     &K32OBJ_NullOps,        /* K32OBJ_MAILSLOT */
51     &K32OBJ_DefaultOps,     /* K32OBJ_TOOLHELP_SNAPSHOT */
52     &K32OBJ_NullOps         /* K32OBJ_SOCKET */
53 };
54
55 typedef struct _NE
56 {
57     struct _NE *next;
58     K32OBJ     *obj;
59     UINT32      len;
60     char        name[1];
61 } NAME_ENTRY;
62
63 static NAME_ENTRY *K32OBJ_FirstEntry = NULL;
64
65
66 /***********************************************************************
67  *           K32OBJ_IncCount
68  */
69 void K32OBJ_IncCount( K32OBJ *ptr )
70 {
71     assert( ptr->type && ((unsigned)ptr->type < K32OBJ_NBOBJECTS) );
72     SYSTEM_LOCK();
73     ptr->refcount++;
74     SYSTEM_UNLOCK();
75     assert( ptr->refcount > 0 );  /* No wrap-around allowed */
76 }
77
78
79 /***********************************************************************
80  *           K32OBJ_DecCount
81  */
82 void K32OBJ_DecCount( K32OBJ *ptr )
83 {
84     NAME_ENTRY **pptr;
85
86     assert( ptr->type && ((unsigned)ptr->type < K32OBJ_NBOBJECTS) );
87     assert( ptr->refcount > 0 );
88     SYSTEM_LOCK();
89     if (--ptr->refcount)
90     {
91         SYSTEM_UNLOCK();
92         return;
93     }
94
95     /* Check if the object has a name entry and free it */
96
97     pptr = &K32OBJ_FirstEntry;
98     while (*pptr && ((*pptr)->obj != ptr)) pptr = &(*pptr)->next;
99     if (*pptr)
100     {
101         NAME_ENTRY *entry = *pptr;
102         *pptr = entry->next;
103         HeapFree( SystemHeap, 0, entry );
104     }
105
106     /* Free the object */
107
108     if (K32OBJ_Ops[ptr->type]->destroy) K32OBJ_Ops[ptr->type]->destroy( ptr );
109     SYSTEM_UNLOCK();
110 }
111
112
113 /***********************************************************************
114  *           K32OBJ_Destroy
115  *
116  * Generic destroy functions for objects that don't need any special treatment.
117  */
118 static void K32OBJ_Destroy( K32OBJ *obj )
119 {
120     obj->type = K32OBJ_UNKNOWN;
121     HeapFree( SystemHeap, 0, obj );
122 }
123
124
125 /***********************************************************************
126  *           K32OBJ_IsValid
127  *
128  * Check if a pointer is a valid kernel object
129  */
130 BOOL32 K32OBJ_IsValid( K32OBJ *ptr, K32OBJ_TYPE type )
131 {
132     if (IsBadReadPtr32( ptr, sizeof(*ptr) )) return FALSE;
133     return (ptr->type == type);
134 }
135
136
137 /***********************************************************************
138  *           K32OBJ_AddName
139  *
140  * Add a name entry for an object. We don't check for duplicates here.
141  * FIXME: should use some sort of hashing.
142  */
143 BOOL32 K32OBJ_AddName( K32OBJ *obj, LPCSTR name )
144 {
145     NAME_ENTRY *entry;
146     UINT32 len;
147
148     if (!name) return TRUE;  /* Anonymous object */
149     len = strlen( name );
150     SYSTEM_LOCK();
151     if (!(entry = HeapAlloc( SystemHeap, 0, sizeof(NAME_ENTRY) + len )))
152     {
153         SYSTEM_UNLOCK();
154         SetLastError( ERROR_OUTOFMEMORY );
155         return FALSE;
156     }
157     entry->next = K32OBJ_FirstEntry;
158     entry->obj  = obj;
159     entry->len  = len;
160     lstrcpy32A( entry->name, name );
161     K32OBJ_FirstEntry = entry;
162     SYSTEM_UNLOCK();
163     return TRUE;
164 }
165
166
167 /***********************************************************************
168  *           K32OBJ_Create
169  *
170  * Create a named kernel object.
171  * Returns NULL if there was an error _or_ if the object already existed.
172  * The refcount of the object must be decremented once it is initialized.
173  */
174 K32OBJ *K32OBJ_Create( K32OBJ_TYPE type, DWORD size, LPCSTR name, int server_handle,
175                        DWORD access, SECURITY_ATTRIBUTES *sa, HANDLE32 *handle)
176 {
177     BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
178
179     /* Check if the name already exists */
180
181     K32OBJ *obj = K32OBJ_FindName( name );
182     if (obj)
183     {
184         if (obj->type == type)
185         {
186             SetLastError( ERROR_ALREADY_EXISTS );
187             *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, server_handle );
188         }
189         else
190         {
191             SetLastError( ERROR_DUP_NAME );
192             *handle = INVALID_HANDLE_VALUE32;
193             if (server_handle != -1) CLIENT_CloseHandle( server_handle );
194         }
195         K32OBJ_DecCount( obj );
196         return NULL;
197     }
198
199     /* Create the object */
200
201     SYSTEM_LOCK();
202     if (!(obj = HeapAlloc( SystemHeap, 0, size )))
203     {
204         SYSTEM_UNLOCK();
205         *handle = INVALID_HANDLE_VALUE32;
206         if (server_handle != -1) CLIENT_CloseHandle( server_handle );
207         return NULL;
208     }
209     obj->type     = type;
210     obj->refcount = 1;
211
212     /* Add a name for it */
213
214     if (!K32OBJ_AddName( obj, name ))
215     {
216         /* Don't call the destroy function, as the object wasn't
217          * initialized properly */
218         HeapFree( SystemHeap, 0, obj );
219         SYSTEM_UNLOCK();
220         *handle = INVALID_HANDLE_VALUE32;
221         if (server_handle != -1) CLIENT_CloseHandle( server_handle );
222         return NULL;
223     }
224
225     /* Allocate a handle */
226
227     *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, server_handle );
228     SYSTEM_UNLOCK();
229     return obj;
230 }
231
232
233 /***********************************************************************
234  *           K32OBJ_FindName
235  *
236  * Find the object referenced by a given name.
237  * The reference count is incremented.
238  */
239 K32OBJ *K32OBJ_FindName( LPCSTR name )
240 {
241     NAME_ENTRY *entry;
242     UINT32 len;
243
244     if (!name) return NULL;  /* Anonymous object */
245     len = strlen( name );
246     SYSTEM_LOCK();
247     entry = K32OBJ_FirstEntry;
248     while (entry)
249     {
250         if ((len == entry->len) && !strcmp( name, entry->name))
251         {
252             K32OBJ *obj = entry->obj;
253             K32OBJ_IncCount( obj );
254             SYSTEM_UNLOCK();
255             return entry->obj;
256         }
257         entry = entry->next;
258     }
259     SYSTEM_UNLOCK();
260     return NULL;
261 }
262
263
264 /***********************************************************************
265  *           K32OBJ_FindNameType
266  *
267  * Find an object by name and check its type.
268  * The reference count is incremented.
269  */
270 K32OBJ *K32OBJ_FindNameType( LPCSTR name, K32OBJ_TYPE type )
271 {
272     K32OBJ *obj = K32OBJ_FindName( name );
273     if (!obj) return NULL;
274     if (obj->type == type) return obj;
275     SetLastError( ERROR_DUP_NAME );
276     K32OBJ_DecCount( obj );
277     return NULL;
278 }