doors.c

来自「Sun公司Dream项目」· C语言 代码 · 共 679 行 · 第 1/2 页

C
679
字号
/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the "License").  You may not use this file except
 * in compliance with the License.
 *
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.php
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * HEADER in each file and include the License file at
 * http://www.opensource.org/licenses/cddl1.php.  If 
 * applicable, add the following below this CDDL HEADER, 
 * with the fields enclosed by brackets "[]" replaced 
 * with your own identifying information: 
 * Portions Copyright [yyyy]
 * [name of copyright owner]
 */ 

/*
 * $(@)Doors.c $Revision: 1.2 $ $Date: 2006/07/15 00:02:33 $
 * 
 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
 */
/*
 * Copyright (c) 1998 by Sun Microsystems, Inc.
 */

/*
 * Doors.c -- Object wrapper for Doors RPC.
 */

/*
 * FIXME: Make sure client checks for need to munmap returned data.
 */

#pragma ident "@(#)Doors.c 1.9	99/10/27 SMI"

#if	!defined(DOORS_HEADER)
#define	DOORS_BODY
#define	DOORS_INLINE		extern
#include "cobjs/Doors.h"
#endif					   /* !defined(DOORS_HEADER) */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <door.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <synch.h>
#include <thread.h>
#include <unistd.h>

#include "cobjs/Actor.h"
#include "cobjs/Log.h"
#include "cobjs/Macros.h"
#include "cobjs/Types.h"

/*************************************************************************
 * Defines
 *************************************************************************/

/*
 * WORKAROUND for libdoor bug.  libdoor should pass the door fd to
 * the thread_create func so it could store it somewhere the thread_init_func
 * could find it.  It doesn't, so we're forced to yield() until the
 * door_create thread can set it.
 */
#define	DOORS_BUG			    1
/*
 * WORKAROUND for libdoor bug.  There's no clean mechanism for shutting
 * down private door threads (ideally, doing a door_revoke() would cause
 * private threads to thr_exit() when they re-entered the private pool).
 * The first workaround was to do "self" door calls that were specially
 * detected in the server func as close shutdowns on the server thread.
 * This works "most" of the time, but occasionally the kernel seems to
 * block this self door_call even though a thread still exists.  This
 * seems to happen mostly when the thread init call occurs close to
 * the self door_call.  The hack here is to ensure that all thread_init's
 * (and the corresponding door_bind()) is done well before the self
 * door_call.
 */
#define	DOORS_BUG2			    1

#define	DOORS_DEFAULT_MAX_THREAD_COUNT	    5

/*************************************************************************
 * Instance Variables
 *************************************************************************/

struct _Doors {
    Object		delegate;
    DoorsThreadInitFunc	threadInitFunc;
    DoorsServerFunc	serverFunc;
    DoorsNoClientFunc	noClientFunc;
    size_t		stackSize;
    int			maxThreadCount;

    u_int		attributes;
    int			fd;
    door_id_t		id;
    char		*file;

    mutex_t		lock;
#if DOORS_BUG
    Boolean		isInitialized;
    cond_t		initializedCond;
#endif /* DOORS_BUG */
#if DOORS_BUG2
    cond_t		pendingCond;
    Boolean		isPendingWait;
    int			pendingCreates;
#endif	/* DOORS_BUG2 */
    int			threadCount;
    Boolean		doingNoClient;
    Boolean		doingShutdown;
    Boolean		doTrace;
};

/*************************************************************************
 * Private types and prototypes referenced from inlines
 *************************************************************************/

/*
 * Use INLINE_PRIVATE if non-inline-able, define in Non-inlinable section
 * Use static if inline-able, define in Private Inline-able section
 *
 * INLINE_PRIVATE void doorsInlinePrivate(void);
 */

typedef enum DoorsCommand {
    DOORS_COMMAND_NO_CLIENT
} DoorsCommand;

typedef struct DoorsParameters {
    DoorsCommand	command;
    Doors		doors;
} DoorsParameters;

typedef struct DoorBuffer {
    void	       *body;
    size_t		size;
} DoorBuffer;

/*************************************************************************
 * Private class data referenced from inlines
 *************************************************************************/

/*************************************************************************
 * Inline Methods
 *************************************************************************/

DOORS_INLINE door_id_t
doorsId(Doors doors)
{
    return doors->id;
}

DOORS_INLINE int
doorsFd(Doors doors)
{
    return doors->fd;
}

DOORS_INLINE int
doorsThreadCount(Doors doors)
{
    return doors->threadCount;
}

DOORS_INLINE DoorsResultData
doorsResultData(void *datap, size_t dataSize, door_desc_t *descp, size_t nDesc)
{
    DoorsResultData drd;

    drd.dataPtr = datap;
    drd.dataSize = dataSize;
    drd.descPtr = descp;
    drd.nDesc = nDesc;
    return drd;
}

DOORS_INLINE unsigned long
doorsIdKeyHash(const void *key, unsigned int *rehashp)
{
    door_id_t doorId = *(door_id_t *)key;
    *rehashp = (unsigned int) ((doorId * 1103515245L + 12345) >> 16);
    return ((unsigned long) (doorId * 123821)) >> 10;
}

DOORS_INLINE Boolean
doorsIdKeyIsEqual(const void *key1, const void *key2)
{
    return Boolean( *(door_id_t *)key1 == *(door_id_t *)key2 );
}

DOORS_INLINE int
doorsIdKeyCmp(const void *key1, const void *key2)
{
    return *(door_id_t *)key1 - *(door_id_t *)key2;
}

/* ARGSUSED1 */
DOORS_INLINE const void *
doorsIdKeyDup(const void *key, const void *value)
{
    door_id_t *newIdp = NEW(door_id_t, 1);
    *newIdp = *(door_id_t *)key;
    return newIdp;
}

DOORS_INLINE void
doorsIdKeyFree(void *key)
{
    free(key);
}

/*************************************************************************
 * Private Inlineable Methods and Functions Called From Inlines
 *************************************************************************/

#if	!defined(DOORS_HEADER)

/*************************************************************************
 * Private types
 *************************************************************************/

/*************************************************************************
 * Private method prototypes
 *************************************************************************/

#ifdef __cplusplus 
extern "C" {
#endif 

static void *doorsThreadInit(void *arg);
static void doorsServerFunc(void *cookie, /*const void*/ char *argp, size_t argSize,
	/*const*/ door_desc_t *descp, size_t nDesc);

/*************************************************************************
 * Private function prototypes
 *************************************************************************/
   
static void doorsThreadCreate(/*const*/ door_info_t *dip);
static void doorsCommandImpl(Actor actor, void *implArg);
static void doorBufferFree(void *arg);

#ifdef __cplusplus
}
#endif
/*************************************************************************
 * Private class data
 *************************************************************************/

static DoorsResultData	nullRetData = { NULL, 0, NULL, 0};
static Actor		commandActor;
static thread_key_t	resultBufferKey;
static thread_key_t	descBufferKey;
static Action		noClientAction;
static pid_t		doorsPid;

/*************************************************************************
 * Class Methods
 *************************************************************************/

void
doorsInit(void)
{
    doorsPid = getpid();
    (void) door_server_create(doorsThreadCreate);
    noClientAction = NEW_ACTION(DoorsParameters, NULL);
    commandActor = actorNew(doorsCommandImpl, NULL, NULL, NULL, 0,
	ACTOR_TYPE_LWP);
    ABORT_IF_ERRNO(thr_keycreate(&resultBufferKey, doorBufferFree));
    ABORT_IF_ERRNO(thr_keycreate(&descBufferKey, doorBufferFree));
}

void
doorsFini(void)
{
    actorFree(commandActor);
    actionFree(noClientAction);
}

Doors
doorsNew(Object delegate, DoorsThreadInitFunc threadInitFunc,
	 DoorsServerFunc serverFunc, DoorsNoClientFunc noClientFunc,
	 size_t stackSize, int maxThreadCount)
{
    Doors doors = NEW_ZEROED(struct _Doors, 1);
    door_info_t info;

    if (maxThreadCount == 0) {
	maxThreadCount = DOORS_DEFAULT_MAX_THREAD_COUNT;
    }

    if (commandActor == NULL) {
	ABORT("doorsInit not called");
    }
    doors->delegate = delegate;
    doors->threadInitFunc = threadInitFunc;
    doors->serverFunc = serverFunc;
    doors->noClientFunc = noClientFunc;
    doors->stackSize = stackSize;
    doors->maxThreadCount = maxThreadCount;

    /*
     * You MUST have private threads until door_revoke() can block
     * until no thread active on door.
     */
    doors->attributes = DOOR_PRIVATE;
    if (noClientFunc != NULL) {
	doors->attributes |= DOOR_UNREF;
    }

    CHECK_IF_ERRNO(mutex_init(&doors->lock, USYNC_THREAD, 0));
    doors->threadCount = 0;
    doors->doingShutdown = FALSE;
    doors->doingNoClient = FALSE;
    doors->doTrace = FALSE;
#if DOORS_BUG
    CHECK_IF_ERRNO(cond_init(&doors->initializedCond, USYNC_THREAD, 0));
    doors->isInitialized = FALSE;
#endif	/* DOORS_BUG */
#if DOORS_BUG2
    CHECK_IF_ERRNO(cond_init(&doors->pendingCond, USYNC_THREAD, 0));
    doors->pendingCreates = 0;
    doors->isPendingWait = FALSE;
#endif	/* DOORS_BUG2 */

    LOG_DBG(('r', "doorsNew(0x%llx, 0x%x)", doors->id, thr_self()));
    ABORT_ON_ERRNO(doors->fd = door_create(doorsServerFunc, doors,
	doors->attributes));
    ABORT_ON_ERRNO(door_info(doors->fd, &info));
    doors->id = info.di_uniquifier;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?