doors.c

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

C
679
字号
    LOG_DBG(('r', "doorsNew(0x%llx, 0x%x)", doors->id, thr_self()));
#if DOORS_BUG
    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    doors->isInitialized = TRUE;
    CHECK_IF_ERRNO(cond_broadcast(&doors->initializedCond));
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
#endif	/* DOORS_BUG */
    return doors;
}

Doors
doorsNewWithFile(Object delegate, DoorsThreadInitFunc threadInitFunc,
	 DoorsServerFunc serverFunc, DoorsNoClientFunc noClientFunc,
	 size_t stackSize, int maxThreadCount, const char *file, uid_t uid,
	 gid_t gid, mode_t mode)
{
    Doors doors = doorsNew(delegate, threadInitFunc, serverFunc, noClientFunc,
	    stackSize, maxThreadCount);
    int fd;

    (void) unlink(file);
    if ((fd = open(file, O_RDWR | O_CREAT | O_NOCTTY, mode)) < 0) {
	logLibErrno(cobjs_TEXT_DOMAIN, "FATAL: open(%s)", file);
	abort();
    }
    ABORT_ON_ERRNO(fchmod(fd, mode));
    ABORT_ON_ERRNO(fchown(fd, uid, gid));
    (void) close(fd);

    if (fattach(doors->fd, file) < 0) {
	logLibErrno(cobjs_TEXT_DOMAIN, "FATAL: fattach(%s)", file);
	abort();
    }
    doors->file = strdup(file);
    return doors;
}

/*************************************************************************
 * Instance Methods
 *************************************************************************/

void         *
doorsResultBuffer(size_t size, size_t count)
{
    DoorBuffer *dbp;

    ABORT_IF_ERRNO(thr_getspecific(resultBufferKey, (void **)&dbp));
    if (dbp == NULL) {
	dbp = NEW_ZEROED(DoorBuffer, 1);
	ABORT_IF_ERRNO(thr_setspecific(resultBufferKey, dbp));
    }
    if (dbp->size < count * size) {
	dbp->body = REALLOC(dbp->body, count, size);
	dbp->size = count * size;
    }
    return dbp->body;
}

door_desc_t *
doorsDescBuffer(size_t count)
{
    DoorBuffer *dbp;

    ABORT_IF_ERRNO(thr_getspecific(descBufferKey, (void **)&dbp));
    if (dbp == NULL) {
	dbp = NEW_ZEROED(DoorBuffer, 1);
	ABORT_IF_ERRNO(thr_setspecific(descBufferKey, dbp));
    }
    if (dbp->size < count * sizeof(door_desc_t)) {
	dbp->body = REALLOC(dbp->body, count, sizeof(door_desc_t));
	dbp->size = count * sizeof(door_desc_t);
    }
    return (door_desc_t *)dbp->body;
}

void
doorsNoClient(Doors doors)
{
    DoorsParameters p;
    Boolean doShutdown = FALSE;

    LOG_DBG(('r', "doorsNoClient(0x%llx, 0x%x)", doors->id,
		thr_self()));
    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    if (! doors->doingNoClient) {
	doors->doingNoClient = TRUE;
	doShutdown = TRUE;
    }
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));

    if (doShutdown) {
	LOG_DBG(('r', "doorsNoClient(0x%llx, 0x%x) shutdown", doors->id,
		    thr_self()));
	p.command = DOORS_COMMAND_NO_CLIENT;
	p.doors = doors;
	actionInitiate(noClientAction, commandActor, &p,
		ACTION_TYPE_NO_RESULTS);
    }
}

void
doorsSetTrace(Doors doors, Boolean doTrace)
{
    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    doors->doTrace = doTrace;
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
}

void
doorsFree(Doors doors)
{
    if (doors->file != NULL) {
	ABORT_ON_ERRNO(fdetach(doors->file));
	free(doors->file);
    }

    /*
     * Terminate threads in private pool
     */
    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    LOG_DBG(('r', "doorsFree(0x%llx, 0x%x) called, count %d", doors->id,
		thr_self(), doors->threadCount));
    ASSERT(! doors->doingShutdown);
    doors->doingShutdown = TRUE;
#if	DOORS_BUG2
    doors->isPendingWait = TRUE;
    while (doors->pendingCreates > 0) {
	LOG_DBG(('r', "doorsFree(0x%llx, 0x%x) pending wait, pending %d",
		    doors->id, thr_self(), doors->pendingCreates));
	CHECK_IF_ERRNO(cond_wait(&doors->pendingCond, &doors->lock));
    }
#endif	/* DOORS_BUG2 */
    while (doors->threadCount > 0) {
	LOG_DBG(('r', "doorsFree(0x%llx, 0x%x), doorCall start count %d",
		    doors->id, thr_self(), doors->threadCount));
	CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
	/*
	 * Do door_calls on all threads, doorsServerFunc sees shutdown TRUE
	 * and if the door_call() was from this pid, does a thr_exit().
	 */
	(void)door_call(doors->fd, NULL);
	CHECK_IF_ERRNO(mutex_lock(&doors->lock));
	LOG_DBG(('r', "doorsFree(0x%llx, 0x%x), doorCall done count %d",
		    doors->id, thr_self(), doors->threadCount));
    }
    LOG_DBG(('r', "doorsFree(0x%llx, 0x%x), door revoke", doors->id,
		thr_self()));
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));

    ABORT_ON_ERRNO(door_revoke(doors->fd));
    LOG_DBG(('r', "doorsFree(0x%llx, 0x%x), door revoke done", doors->id,
		thr_self()));

#if DOORS_BUG
    CHECK_IF_ERRNO(cond_destroy(&doors->initializedCond));
#endif	/* DOORS_BUG */
#if DOORS_BUG2
    CHECK_IF_ERRNO(cond_destroy(&doors->pendingCond));
#endif	/* DOORS_BUG2 */
    CHECK_IF_ERRNO(mutex_destroy(&doors->lock));
    free(doors);
}

/*************************************************************************
 * Private Methods
 *************************************************************************/

/*
 * Non-inlinable called from inline
 *
 * INLINE_PRIVATE void
 * doorsInlinePrivate(void)
 * {
 * }
 */

static void *
doorsThreadInit(void *arg)
{
    Doors doors = (Doors) arg;

#if DOORS_BUG
    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    while (! doors->isInitialized) {
	CHECK_IF_ERRNO(cond_wait(&doors->initializedCond, &doors->lock));
    }
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
#endif /* DOORS_BUG */

    LOG_DBG(('r', "doorsThreadInit(0x%llx, 0x%x)", doors->id, thr_self()));

    if (doors->threadInitFunc != NULL) {
	(*doors->threadInitFunc)(doors->delegate);
    }
    LOG_DBG(('r', "doorsThreadInit(0x%llx, 0x%x) door_bind", doors->id,
		thr_self()));
    ABORT_ON_ERRNO(door_bind(doors->fd));
    LOG_DBG(('r', "doorsThreadInit(0x%llx, 0x%x) door_bind done", doors->id,
		thr_self()));
    ABORT_IF_ERRNO(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
    LOG_DBG(('r', "doorsThreadInit(0x%llx, 0x%x) door_return", doors->id,
		thr_self()));
#if DOORS_BUG2
    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    ASSERT(doors->pendingCreates > 0);
    if (--doors->pendingCreates == 0 && doors->isPendingWait) {
	CHECK_IF_ERRNO(cond_broadcast(&doors->pendingCond));
    }
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
#endif	/* DOORS_BUG2 */
    ABORT_ON_ERRNO(door_return(NULL, 0, NULL, 0));
    return NULL;	/* for lint */
}

static void
doorsServerFunc(void *cookie, /*const void*/ char *argp, size_t argSize,
	/*const*/ door_desc_t *descp, size_t nDesc)
{
    Doors doors = (Doors) cookie;
    DoorsResultData retData;

    if (argp == DOOR_UNREF_DATA) {
	ASSERT(doors->noClientFunc != NULL);
	LOG_DBG(('r', "doorsServerFunc(0x%llx, 0x%x) UNREF DOOR",
		    doors->id, thr_self()));
	doorsNoClient(doors);
	retData = nullRetData;
    } else {
	door_cred_t cred;

	if (door_cred(&cred) != 0) {
	    LOG_DBG(('r', "doorsServerFunc(0x%llx, 0x%x) cred failed",
		    doors->id, thr_self()));
	    switch (errno) {
	    case EINVAL:
		/*
		 * This can happen if client is aborted between start
		 * of door call and here....  Just ignore the request
		 * (thr_exit??).
		 */
		retData = nullRetData;
		break;
	    default:
		ABORT_WITH_ERRNO(errno, "door_cred");
		break;
	    }
	} else {
	    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
	    if (doors->doingShutdown && cred.dc_pid == doorsPid) {
		/*
		 * If doing shutdown, request is from ourself, then
		 * terminate this thread.  See doorsFree().
		 */
		doors->threadCount -= 1;
		ASSERT(doors->threadCount >= 0);
		LOG_DBG(('r', "doorsServerFunc(0x%llx, 0x%x) thr_exit count %d",
			    doors->id, thr_self(), doors->threadCount));
		CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
		thr_exit(NULL);
	    }
	    LOG_DBGC((doors->doTrace, 'r',
			"doorsServerFunc(0x%llx, 0x%x) do request",
			doors->id, thr_self()));
	    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
	    retData = (*doors->serverFunc)(doors->delegate, doors, argp,
		    argSize, descp, nDesc, &cred);
	}
    }
    ABORT_ON_ERRNO(door_return((char *)retData.dataPtr, retData.dataSize,
	retData.descPtr, retData.nDesc));
}

/*************************************************************************
 * Private Functions
 *************************************************************************/

static void
doorsThreadCreate(/*const*/ door_info_t *dip)
{
    Doors doors = (Doors) dip->di_data;

    CHECK_IF_ERRNO(mutex_lock(&doors->lock));
    LOG_DBG(('r', "doorsThreadCreate(0x%llx, 0x%x)", doors->id, thr_self()));
    if (doors->threadCount >= doors->maxThreadCount || doors->doingShutdown) {
	LOG_DBG(('r', "doorsThreadCreate(0x%llx, 0x%x) rejected count %d",
		    doors->id, thr_self(), doors->threadCount));
	CHECK_IF_ERRNO(mutex_unlock(&doors->lock));
	return;
    }
    doors->threadCount += 1;
    LOG_DBG(('r', "doorsThreadCreate(0x%llx, 0x%x) accepted count %d",
		doors->id, thr_self(), doors->threadCount));
#if DOORS_BUG2
    doors->pendingCreates += 1;
#endif	/* DOORS_BUG2 */
    CHECK_IF_ERRNO(mutex_unlock(&doors->lock));

    ABORT_IF_ERRNO(thr_create(NULL, doors->stackSize, doorsThreadInit, doors,
	THR_BOUND | THR_DETACHED, NULL));
}

/* ARGSUSED1 */
static void
doorsCommandImpl(Actor actor, void *implArg)
{
    while (actorIsRunning(actor)) {
	Action action = actorGetAction(actor, NULL);
	if (action != NULL) {
	    DoorsParameters *p = (DoorsParameters *)actionGetParameterp(action);
	    Doors doors = p->doors;

	    switch (p->command) {
	    case DOORS_COMMAND_NO_CLIENT:
		/*
		 * We expect the noClientFunc to do a doorsFree
		 */
		(*doors->noClientFunc)(doors->delegate);
		actionDone(action);
		break;
	    default:
		ABORT("unknown doorsCommand");
	    }
	}
    }
}

static void
doorBufferFree(void *arg)
{
    DoorBuffer *dbp = (DoorBuffer *)arg;

    if (dbp->body != NULL) {
	free(dbp->body);
    }
    free(dbp);
}

#endif					   /* !defined(DOORS_HEADER) */

⌨️ 快捷键说明

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