/*
* Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: edbreq.c,v 1.31 2006/12/29 01:28:09 ca Exp $")
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/heap.h"
#include "sm/assert.h"
#include "sm/str.h"
#include "sm/edb.h"
#include "edb-int.h"
#include "sm/pthread.h"
#include "log.h"
/* DEBUGGING */
#include "sm/io.h"
/*
** EDB_REQ_NEW -- get new edb request
** (from list of available edb requests or allocate a new one)
**
** Parameters:
** edb_ctx -- EDB context
** pedb_req -- edb req (output)
** flags -- flags (EDB_RQF_*)
** lockit -- lock edb_ctx? (reql_pool)
**
** Returns:
** usual sm_error code; ENOMEM, (un)lock
**
** Side Effects: none on error (except if unlock fails)
**
** Locking: locks edb_ctx if requested (note: don't use locktype because
** unlock on error can't work as unlock happens before an
** error may occur).
**
** Last code review: 2005-03-17 23:44:31
** Last code change: 2005-03-17 23:17:09
*/
sm_ret_T
edb_req_new(edb_ctx_P edb_ctx, uint32_t flags, edb_req_P *pedb_req, bool lockit)
{
int r;
sm_ret_T ret;
edb_req_P edb_req;
edb_req_hd_P edb_reql;
SM_REQUIRE(pedb_req != NULL);
if (lockit) {
r = pthread_mutex_lock(&edb_ctx->edb_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_EDB, r);
}
ret = SM_SUCCESS;
#if SM_REQL_FLE
if (SM_IS_FLAG(flags, EDB_RQF_EMERG))
edb_reql = &edb_ctx->edb_reql_fle;
else
#endif
if (SM_IS_FLAG(flags, EDB_RQF_SMALL))
edb_reql = &edb_ctx->edb_reql_fls;
else
edb_reql = &edb_ctx->edb_reql_fln;
if (!EDBREQL_EMPTY(edb_reql) && !SM_IS_FLAG(flags, EDB_RQF_ALLOC)) {
edb_req = EDBREQL_FIRST(edb_reql);
EDBREQL_REMOVE(edb_reql);
if (lockit) {
r = pthread_mutex_unlock(&edb_ctx->edb_mutex);
SM_ASSERT(0 == r);
if (r != 0)
ret = sm_error_perm(SM_EM_EDB, r);
}
}
else {
if (lockit) {
r = pthread_mutex_unlock(&edb_ctx->edb_mutex);
SM_ASSERT(0 == r);
if (r != 0)
ret = sm_error_perm(SM_EM_EDB, r);
}
edb_req = (edb_req_P) sm_zalloc(sizeof(*edb_req));
if (NULL == edb_req)
return sm_error_temp(SM_EM_EDB, ENOMEM);
edb_req->edb_req_rcb = sm_rcb_new(NULL,
SM_IS_FLAG(flags, EDB_RQF_SMALL)
? EDB_RC_SMALLSZ : EDB_RC_SZ,
EDB_RC_MAXSZ);
if (NULL == edb_req->edb_req_rcb) {
sm_free_size(edb_req, sizeof(*edb_req));
return sm_error_temp(SM_EM_EDB, ENOMEM);
}
}
*pedb_req = edb_req;
return ret;
}
/*
** EDB_REQ_REL -- release edb request: clear out data, put it into pool
**
** Parameters:
** edb_ctx -- EDB context
** edb_req -- edb req
** flags -- flags (EDB_RQF_*)
** locktype -- kind of locking (edb_ctx (reql_pool))
**
** Returns:
** SM_SUCCESS except for (un)lock errors
**
** Locking: check unlocking! XXX
**
** Last code review: 2005-03-23 19:58:11
** Last code change:
*/
sm_ret_T
edb_req_rel(edb_ctx_P edb_ctx, edb_req_P edb_req, uint32_t flags, thr_lock_T locktype)
{
int r;
sm_ret_T ret;
edb_req_hd_P edb_reql;
if (NULL == edb_req)
return SM_SUCCESS;
if (SM_IS_FLAG(flags, EDB_RQF_FREE))
return edb_req_free(edb_req);
SM_IS_EDB_CTX(edb_ctx);
if (thr_lock_it(locktype)) {
r = pthread_mutex_lock(&edb_ctx->edb_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_EDB, r);
}
ret = SM_SUCCESS;
#if SM_REQL_FLE
if (SM_IS_FLAG(flags, EDB_RQF_EMERG))
edb_reql = &edb_ctx->edb_reql_fle;
else
#endif
if (sm_rcb_getsize(edb_req->edb_req_rcb) <= EDB_RC_SMALLSZ)
edb_reql = &edb_ctx->edb_reql_fls;
else
edb_reql = &edb_ctx->edb_reql_fln;
EDBREQL_PRE(edb_reql, edb_req);
if (thr_unl_no_err(locktype)) {
r = pthread_mutex_unlock(&edb_ctx->edb_mutex);
SM_ASSERT(0 == r);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_EDB, r);
}
return ret;
}
/*
** EDB_REQ_FREE -- free edb request
**
** Parameters:
** edb_req -- edb req
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-03-23 19:49:42
** Last code change:
*/
sm_ret_T
edb_req_free(edb_req_P edb_req)
{
if (NULL == edb_req)
return SM_SUCCESS;
if (edb_req->edb_req_rcb != NULL)
sm_rcb_free(edb_req->edb_req_rcb);
sm_free_size(edb_req, sizeof(*edb_req));
return SM_SUCCESS;
}
/*
** EDB_REQLS_FREE -- free edb request lists that are controlled by edb_ctx
**
** Parameters:
** edb_ctx -- EDB context
**
** Returns:
** SM_SUCCESS
**
** Side Effects:
** calls edb_wr_status() is wr list is not empty!
**
** Locking:
** edb_ctx (reql_wr, reql_pool) must be locked by caller
**
** Last code review: 2005-04-04 16:37:33
** Last code change: 2005-04-04 16:37:30
*/
sm_ret_T
edb_reqls_free(edb_ctx_P edb_ctx)
{
edb_req_P edb_req;
SM_IS_EDB_CTX(edb_ctx);
/* This should be empty!!! */
if (!EDBREQL_EMPTY(&edb_ctx->edb_reql_wr)) {
sm_log_write(edb_ctx->edb_lctx,
EDB_LCAT_EDB, EDB_LMOD_EDB, SM_LOG_ERR, 4,
"sev=ERROR, func=edb_reqls_free, edb_reql_wr=NOT_empty");
/* XXX Write list anyway? */
edb_wr_status(edb_ctx, NULL);
}
while (!EDBREQL_EMPTY(&edb_ctx->edb_reql_fln)) {
edb_req = EDBREQL_FIRST(&edb_ctx->edb_reql_fln);
EDBREQL_REMOVE(&edb_ctx->edb_reql_fln);
edb_req_free(edb_req);
}
while (!EDBREQL_EMPTY(&edb_ctx->edb_reql_fls)) {
edb_req = EDBREQL_FIRST(&edb_ctx->edb_reql_fls);
EDBREQL_REMOVE(&edb_ctx->edb_reql_fls);
edb_req_free(edb_req);
}
#if SM_REQL_FLE
while (!EDBREQL_EMPTY(&edb_ctx->edb_reql_fle)) {
edb_req = EDBREQL_FIRST(&edb_ctx->edb_reql_fle);
EDBREQL_REMOVE(&edb_ctx->edb_reql_fle);
edb_req_free(edb_req);
}
#endif
return SM_SUCCESS;
}
/*
** EDB_REQL_FREE -- free edb request list (not put back in pool)
**
** Parameters:
** edb_ctx -- EDB context (unused)
** edb_req_hd -- head of request list for (DEF)EDB
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-03-23 19:55:35; see comments below
** Last code change:
*/
sm_ret_T
edb_reql_free(edb_ctx_P edb_ctx, edb_req_hd_P edb_req_hd)
{
edb_req_P edb_req;
SM_REQUIRE(edb_req_hd != NULL);
while (!EDBREQL_EMPTY(edb_req_hd)) {
/*
** Complain? Call function to write this out?
** Add a parameter which indicates whether this is
** a "cancel" (just free the data) or a write+free?
*/
edb_req = EDBREQL_FIRST(edb_req_hd);
EDBREQL_REMOVE(edb_req_hd);
edb_req_free(edb_req);
}
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1