Ejemplo n.º 1
0
wtiCancelThrd(wti_t *pThis, const uchar *const cancelobj)
{
	DEFiRet;

	ISOBJ_TYPE_assert(pThis, wti);

	if(wtiGetState(pThis)) {
		LogMsg(0, RS_RET_ERR, LOG_WARNING, "%s: need to do cooperative cancellation "
			"- some data may be lost, increase timeout?", cancelobj);
		/* we first try the cooperative "cancel" interface */
		pthread_kill(pThis->thrdID, SIGTTIN);
		DBGPRINTF("sent SIGTTIN to worker thread %p, giving it a chance to terminate\n",
			(void *) pThis->thrdID);
		srSleep(0, 10000);
	}

	if(wtiGetState(pThis)) {
		LogMsg(0, RS_RET_ERR, LOG_WARNING, "%s: need to do hard cancellation", cancelobj);
		DBGPRINTF("cooperative worker termination failed, using cancellation...\n");
		DBGOPRINT((obj_t*) pThis, "canceling worker thread\n");
		pthread_cancel(pThis->thrdID);
		/* now wait until the thread terminates... */
		while(wtiGetState(pThis)) {
			srSleep(0, 10000);
		}
	}

	RETiRet;
}
Ejemplo n.º 2
0
/* Cancel the thread. If the thread is not running. But it is save and legal to
 * call wtiCancelThrd() in such situations. This function only returns when the
 * thread has terminated. Else we may get race conditions all over the code...
 * Note that when waiting for the thread to terminate, we do a busy wait, checking
 * progress every 10ms. It is very unlikely that we will ever cancel a thread
 * and, if so, it will only happen at the end of the rsyslog run. So doing this
 * kind of non-optimal wait is considered preferable over using condition variables.
 * rgerhards, 2008-02-26
 */
rsRetVal
wtiCancelThrd(wti_t *pThis)
{
	DEFiRet;

	ISOBJ_TYPE_assert(pThis, wti);


	if(wtiGetState(pThis)) {
		/* we first try the cooperative "cancel" interface */
		pthread_kill(pThis->thrdID, SIGTTIN);
		DBGPRINTF("sent SIGTTIN to worker thread 0x%x, giving it a chance to terminate\n", (unsigned) pThis->thrdID);
		srSleep(0, 10000);
	}

	if(wtiGetState(pThis)) {
		DBGPRINTF("cooperative worker termination failed, using cancellation...\n");
		DBGOPRINT((obj_t*) pThis, "canceling worker thread\n");
		pthread_cancel(pThis->thrdID);
		/* now wait until the thread terminates... */
		while(wtiGetState(pThis)) {
			srSleep(0, 10000);
		}
	}

	RETiRet;
}
Ejemplo n.º 3
0
/* do the physical open() call on a file.
 */
static rsRetVal
doPhysOpen(strm_t *pThis)
{
	int iFlags = 0;
	DEFiRet;
	ISOBJ_TYPE_assert(pThis, strm);

	/* compute which flags we need to provide to open */
	switch(pThis->tOperationsMode) {
		case STREAMMODE_READ:
			iFlags = O_CLOEXEC | O_NOCTTY | O_RDONLY;
			break;
		case STREAMMODE_WRITE:	/* legacy mode used inside queue engine */
			iFlags = O_CLOEXEC | O_NOCTTY | O_WRONLY | O_CREAT;
			break;
		case STREAMMODE_WRITE_TRUNC:
			iFlags = O_CLOEXEC | O_NOCTTY | O_WRONLY | O_CREAT | O_TRUNC;
			break;
		case STREAMMODE_WRITE_APPEND:
			iFlags = O_CLOEXEC | O_NOCTTY | O_WRONLY | O_CREAT | O_APPEND;
			break;
		default:assert(0);
			break;
	}
	if(pThis->sType == STREAMTYPE_NAMED_PIPE) {
		DBGPRINTF("Note: stream '%s' is a named pipe, open with O_NONBLOCK\n", pThis->pszCurrFName);
		iFlags |= O_NONBLOCK;
	}

	pThis->fd = open((char*)pThis->pszCurrFName, iFlags, pThis->tOpenMode);
	DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName, pThis->fd, pThis->tOpenMode);
	if(pThis->fd == -1) {
		char errStr[1024];
		int err = errno;
		rs_strerror_r(err, errStr, sizeof(errStr));
		DBGOPRINT((obj_t*) pThis, "open error %d, file '%s': %s\n", errno, pThis->pszCurrFName, errStr);
		if(err == ENOENT)
			ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
		else
			ABORT_FINALIZE(RS_RET_IO_ERROR);
	} else {
		if(!ustrcmp(pThis->pszCurrFName, UCHAR_CONSTANT(_PATH_CONSOLE)) || isatty(pThis->fd)) {
			DBGPRINTF("file %d is a tty-type file\n", pThis->fd);
			pThis->bIsTTY = 1;
		} else {
			pThis->bIsTTY = 0;
		}
	}

finalize_it:
	RETiRet;
}
Ejemplo n.º 4
0
/* open a strm file
 * It is OK to call this function when the stream is already open. In that
 * case, it returns immediately with RS_RET_OK
 */
static rsRetVal strmOpenFile(strm_t *pThis)
{
	DEFiRet;

	ASSERT(pThis != NULL);

	if(pThis->fd != -1)
		ABORT_FINALIZE(RS_RET_OK);

	if(pThis->pszFName == NULL)
		ABORT_FINALIZE(RS_RET_FILE_PREFIX_MISSING);

	if(pThis->sType == STREAMTYPE_FILE_CIRCULAR) {
		CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
				    pThis->pszFName, pThis->lenFName, pThis->iCurrFNum, pThis->iFileNumDigits));
	} else {
		if(pThis->pszDir == NULL) {
			if((pThis->pszCurrFName = (uchar*) strdup((char*) pThis->pszFName)) == NULL)
				ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
		} else {
			CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
					    pThis->pszFName, pThis->lenFName, -1, 0));
		}
	}

	CHKiRet(doPhysOpen(pThis));

	pThis->iCurrOffs = 0;
	if(pThis->tOperationsMode == STREAMMODE_WRITE_APPEND) {
		/* we need to obtain the current offset */
		off_t offset;
		CHKiRet(getFileSize(pThis->pszCurrFName, &offset));
		pThis->iCurrOffs = offset;
	}

	DBGOPRINT((obj_t*) pThis, "opened file '%s' for %s as %d\n", pThis->pszCurrFName,
		  (pThis->tOperationsMode == STREAMMODE_READ) ? "READ" : "WRITE", pThis->fd);

finalize_it:
	RETiRet;
}
Ejemplo n.º 5
0
/* wait for queue to become non-empty or timeout
 * helper to wtiWorker. Note the the predicate is
 * re-tested by the caller, so it is OK to NOT do it here.
 * rgerhards, 2009-05-20
 */
static void
doIdleProcessing(wti_t *pThis, wtp_t *pWtp, int *pbInactivityTOOccured)
{
	struct timespec t;

	BEGINfunc
	DBGPRINTF("%s: worker IDLE, waiting for work.\n", wtiGetDbgHdr(pThis));

	if(pThis->bAlwaysRunning) {
		/* never shut down any started worker */
		d_pthread_cond_wait(&pThis->pcondBusy, pWtp->pmutUsr);
	} else {
		timeoutComp(&t, pWtp->toWrkShutdown);/* get absolute timeout */
		if(d_pthread_cond_timedwait(&pThis->pcondBusy, pWtp->pmutUsr, &t) != 0) {
			DBGPRINTF("%s: inactivity timeout, worker terminating...\n", wtiGetDbgHdr(pThis));
			*pbInactivityTOOccured = 1; /* indicate we had a timeout */
		}
	}
	DBGOPRINT((obj_t*) pThis, "worker awoke from idle processing\n");
	ENDfunc
}
Ejemplo n.º 6
0
rsRetVal
wtiWorker(wti_t *pThis)
{
	wtp_t *pWtp;		/* our worker thread pool */
	int bInactivityTOOccured = 0;
	rsRetVal localRet;
	rsRetVal terminateRet;
	int iCancelStateSave;
	DEFiRet;

	ISOBJ_TYPE_assert(pThis, wti);
	pWtp = pThis->pWtp; /* shortcut */
	ISOBJ_TYPE_assert(pWtp, wtp);

	dbgSetThrdName(pThis->pszDbgHdr);
	pthread_cleanup_push(wtiWorkerCancelCleanup, pThis);
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave);

	/* now we have our identity, on to real processing */
	while(1) { /* loop will be broken below - need to do mutex locks */
		if(pWtp->pfRateLimiter != NULL) { /* call rate-limiter, if defined */
			pWtp->pfRateLimiter(pWtp->pUsr);
		}
		
		d_pthread_mutex_lock(pWtp->pmutUsr);

		/* first check if we are in shutdown process (but evaluate a bit later) */
		terminateRet = wtpChkStopWrkr(pWtp, MUTEX_ALREADY_LOCKED);
		if(terminateRet == RS_RET_TERMINATE_NOW) {
			/* we now need to free the old batch */
			localRet = pWtp->pfObjProcessed(pWtp->pUsr, pThis);
			DBGOPRINT((obj_t*) pThis, "terminating worker because of TERMINATE_NOW mode, del iRet %d\n",
				 localRet);
			d_pthread_mutex_unlock(pWtp->pmutUsr);
			break;
		}

		/* try to execute and process whatever we have */
		/* Note that this function releases and re-aquires the mutex. The returned
		 * information on idle state must be processed before releasing the mutex again.
		 */
		localRet = pWtp->pfDoWork(pWtp->pUsr, pThis);

		if(localRet == RS_RET_ERR_QUEUE_EMERGENCY) {
			d_pthread_mutex_unlock(pWtp->pmutUsr);
			break;	/* end of loop */
		} else if(localRet == RS_RET_IDLE) {
			if(terminateRet == RS_RET_TERMINATE_WHEN_IDLE || bInactivityTOOccured) {
				d_pthread_mutex_unlock(pWtp->pmutUsr);
				DBGOPRINT((obj_t*) pThis, "terminating worker terminateRet=%d, bInactivityTOOccured=%d\n",
					  terminateRet, bInactivityTOOccured);
				break;	/* end of loop */
			}
			doIdleProcessing(pThis, pWtp, &bInactivityTOOccured);
			d_pthread_mutex_unlock(pWtp->pmutUsr);
			continue; /* request next iteration */
		}

		d_pthread_mutex_unlock(pWtp->pmutUsr);

		bInactivityTOOccured = 0; /* reset for next run */
	}

	/* indicate termination */
	pthread_cleanup_pop(0); /* remove cleanup handler */
	pthread_setcancelstate(iCancelStateSave, NULL);

	RETiRet;
}