mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 20:59:54 +00:00
62a8b43301
Added user APCs support. Many changes to the xterm console to make use of the server (not finished yet). Moved some other small stuff to the server.
281 lines
7.2 KiB
C
281 lines
7.2 KiB
C
/*
|
|
* KERNEL32 objects
|
|
*
|
|
* Copyright 1996 Alexandre Julliard
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include "winerror.h"
|
|
#include "k32obj.h"
|
|
#include "heap.h"
|
|
#include "process.h"
|
|
#include "server.h"
|
|
|
|
|
|
/* The declarations are here to avoid including a lot of unnecessary files */
|
|
extern const K32OBJ_OPS PROCESS_Ops;
|
|
extern const K32OBJ_OPS THREAD_Ops;
|
|
extern const K32OBJ_OPS MEM_MAPPED_FILE_Ops;
|
|
extern const K32OBJ_OPS CONSOLE_Ops;
|
|
extern const K32OBJ_OPS SNAPSHOT_Ops;
|
|
|
|
static const K32OBJ_OPS K32OBJ_NullOps =
|
|
{
|
|
NULL /* destroy */
|
|
};
|
|
|
|
static void K32OBJ_Destroy( K32OBJ *obj );
|
|
|
|
static const K32OBJ_OPS K32OBJ_DefaultOps =
|
|
{
|
|
K32OBJ_Destroy /* destroy */
|
|
};
|
|
|
|
|
|
const K32OBJ_OPS * const K32OBJ_Ops[K32OBJ_NBOBJECTS] =
|
|
{
|
|
NULL,
|
|
&K32OBJ_DefaultOps, /* K32OBJ_SEMAPHORE */
|
|
&K32OBJ_DefaultOps, /* K32OBJ_EVENT */
|
|
&K32OBJ_DefaultOps, /* K32OBJ_MUTEX */
|
|
&K32OBJ_NullOps, /* K32OBJ_CRITICAL_SECTION */
|
|
&PROCESS_Ops, /* K32OBJ_PROCESS */
|
|
&THREAD_Ops, /* K32OBJ_THREAD */
|
|
&K32OBJ_DefaultOps, /* K32OBJ_FILE */
|
|
&K32OBJ_DefaultOps, /* K32OBJ_CHANGE */
|
|
&CONSOLE_Ops, /* K32OBJ_CONSOLE */
|
|
&K32OBJ_NullOps, /* K32OBJ_SCREEN_BUFFER */
|
|
&MEM_MAPPED_FILE_Ops, /* K32OBJ_MEM_MAPPED_FILE */
|
|
&K32OBJ_NullOps, /* K32OBJ_SERIAL */
|
|
&K32OBJ_NullOps, /* K32OBJ_DEVICE_IOCTL */
|
|
&K32OBJ_DefaultOps, /* K32OBJ_PIPE */
|
|
&K32OBJ_NullOps, /* K32OBJ_MAILSLOT */
|
|
&K32OBJ_NullOps, /* K32OBJ_TOOLHELP_SNAPSHOT */
|
|
&K32OBJ_NullOps /* K32OBJ_SOCKET */
|
|
};
|
|
|
|
typedef struct _NE
|
|
{
|
|
struct _NE *next;
|
|
K32OBJ *obj;
|
|
UINT32 len;
|
|
char name[1];
|
|
} NAME_ENTRY;
|
|
|
|
static NAME_ENTRY *K32OBJ_FirstEntry = NULL;
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_IncCount
|
|
*/
|
|
void K32OBJ_IncCount( K32OBJ *ptr )
|
|
{
|
|
assert( ptr->type && ((unsigned)ptr->type < K32OBJ_NBOBJECTS) );
|
|
SYSTEM_LOCK();
|
|
ptr->refcount++;
|
|
SYSTEM_UNLOCK();
|
|
assert( ptr->refcount > 0 ); /* No wrap-around allowed */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_DecCount
|
|
*/
|
|
void K32OBJ_DecCount( K32OBJ *ptr )
|
|
{
|
|
NAME_ENTRY **pptr;
|
|
|
|
assert( ptr->type && ((unsigned)ptr->type < K32OBJ_NBOBJECTS) );
|
|
assert( ptr->refcount > 0 );
|
|
SYSTEM_LOCK();
|
|
if (--ptr->refcount)
|
|
{
|
|
SYSTEM_UNLOCK();
|
|
return;
|
|
}
|
|
|
|
/* Check if the object has a name entry and free it */
|
|
|
|
pptr = &K32OBJ_FirstEntry;
|
|
while (*pptr && ((*pptr)->obj != ptr)) pptr = &(*pptr)->next;
|
|
if (*pptr)
|
|
{
|
|
NAME_ENTRY *entry = *pptr;
|
|
*pptr = entry->next;
|
|
HeapFree( SystemHeap, 0, entry );
|
|
}
|
|
|
|
/* Free the object */
|
|
|
|
if (K32OBJ_Ops[ptr->type]->destroy) K32OBJ_Ops[ptr->type]->destroy( ptr );
|
|
SYSTEM_UNLOCK();
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_Destroy
|
|
*
|
|
* Generic destroy functions for objects that don't need any special treatment.
|
|
*/
|
|
static void K32OBJ_Destroy( K32OBJ *obj )
|
|
{
|
|
obj->type = K32OBJ_UNKNOWN;
|
|
HeapFree( SystemHeap, 0, obj );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_IsValid
|
|
*
|
|
* Check if a pointer is a valid kernel object
|
|
*/
|
|
BOOL32 K32OBJ_IsValid( K32OBJ *ptr, K32OBJ_TYPE type )
|
|
{
|
|
if (IsBadReadPtr32( ptr, sizeof(*ptr) )) return FALSE;
|
|
return (ptr->type == type);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_AddName
|
|
*
|
|
* Add a name entry for an object. We don't check for duplicates here.
|
|
* FIXME: should use some sort of hashing.
|
|
*/
|
|
BOOL32 K32OBJ_AddName( K32OBJ *obj, LPCSTR name )
|
|
{
|
|
NAME_ENTRY *entry;
|
|
UINT32 len;
|
|
|
|
if (!name) return TRUE; /* Anonymous object */
|
|
len = strlen( name );
|
|
SYSTEM_LOCK();
|
|
if (!(entry = HeapAlloc( SystemHeap, 0, sizeof(NAME_ENTRY) + len )))
|
|
{
|
|
SYSTEM_UNLOCK();
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return FALSE;
|
|
}
|
|
entry->next = K32OBJ_FirstEntry;
|
|
entry->obj = obj;
|
|
entry->len = len;
|
|
lstrcpy32A( entry->name, name );
|
|
K32OBJ_FirstEntry = entry;
|
|
SYSTEM_UNLOCK();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_Create
|
|
*
|
|
* Create a named kernel object.
|
|
* Returns NULL if there was an error _or_ if the object already existed.
|
|
* The refcount of the object must be decremented once it is initialized.
|
|
*/
|
|
K32OBJ *K32OBJ_Create( K32OBJ_TYPE type, DWORD size, LPCSTR name, int server_handle,
|
|
DWORD access, SECURITY_ATTRIBUTES *sa, HANDLE32 *handle)
|
|
{
|
|
BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
|
|
|
/* Check if the name already exists */
|
|
|
|
K32OBJ *obj = K32OBJ_FindName( name );
|
|
if (obj)
|
|
{
|
|
if (obj->type == type)
|
|
{
|
|
SetLastError( ERROR_ALREADY_EXISTS );
|
|
*handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, server_handle );
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_DUP_NAME );
|
|
*handle = INVALID_HANDLE_VALUE32;
|
|
if (server_handle != -1) CLIENT_CloseHandle( server_handle );
|
|
}
|
|
K32OBJ_DecCount( obj );
|
|
return NULL;
|
|
}
|
|
|
|
/* Create the object */
|
|
|
|
SYSTEM_LOCK();
|
|
if (!(obj = HeapAlloc( SystemHeap, 0, size )))
|
|
{
|
|
SYSTEM_UNLOCK();
|
|
*handle = INVALID_HANDLE_VALUE32;
|
|
if (server_handle != -1) CLIENT_CloseHandle( server_handle );
|
|
return NULL;
|
|
}
|
|
obj->type = type;
|
|
obj->refcount = 1;
|
|
|
|
/* Add a name for it */
|
|
|
|
if (!K32OBJ_AddName( obj, name ))
|
|
{
|
|
/* Don't call the destroy function, as the object wasn't
|
|
* initialized properly */
|
|
HeapFree( SystemHeap, 0, obj );
|
|
SYSTEM_UNLOCK();
|
|
*handle = INVALID_HANDLE_VALUE32;
|
|
if (server_handle != -1) CLIENT_CloseHandle( server_handle );
|
|
return NULL;
|
|
}
|
|
|
|
/* Allocate a handle */
|
|
|
|
*handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, server_handle );
|
|
SYSTEM_UNLOCK();
|
|
return obj;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_FindName
|
|
*
|
|
* Find the object referenced by a given name.
|
|
* The reference count is incremented.
|
|
*/
|
|
K32OBJ *K32OBJ_FindName( LPCSTR name )
|
|
{
|
|
NAME_ENTRY *entry;
|
|
UINT32 len;
|
|
|
|
if (!name) return NULL; /* Anonymous object */
|
|
len = strlen( name );
|
|
SYSTEM_LOCK();
|
|
entry = K32OBJ_FirstEntry;
|
|
while (entry)
|
|
{
|
|
if ((len == entry->len) && !strcmp( name, entry->name))
|
|
{
|
|
K32OBJ *obj = entry->obj;
|
|
K32OBJ_IncCount( obj );
|
|
SYSTEM_UNLOCK();
|
|
return entry->obj;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
SYSTEM_UNLOCK();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* K32OBJ_FindNameType
|
|
*
|
|
* Find an object by name and check its type.
|
|
* The reference count is incremented.
|
|
*/
|
|
K32OBJ *K32OBJ_FindNameType( LPCSTR name, K32OBJ_TYPE type )
|
|
{
|
|
K32OBJ *obj = K32OBJ_FindName( name );
|
|
if (!obj) return NULL;
|
|
if (obj->type == type) return obj;
|
|
SetLastError( ERROR_DUP_NAME );
|
|
K32OBJ_DecCount( obj );
|
|
return NULL;
|
|
}
|