Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
* @file Cleanup.h
* @brief Easy-to-use utilities to avoid resource leaks or double-releases of resources. Independent of the rest
* of the CPPAPI.
*/
#pragma once
#include <type_traits>
#include <memory>
#include <ts/ts.h>
namespace atscppapi
{
#if defined(X)
#error "X defined as preprocessor symbol"
#endif
#define X(NAME_SEGMENT) \
struct TS##NAME_SEGMENT##Deleter { \
void \
operator()(TS##NAME_SEGMENT ptr) \
{ \
TS##NAME_SEGMENT##Destroy(ptr); \
} \
}; \
using TS##NAME_SEGMENT##UniqPtr = std::unique_ptr<std::remove_pointer_t<TS##NAME_SEGMENT>, TS##NAME_SEGMENT##Deleter>;
#if defined(Y)
#error "Y defined as preprocessor symbol"
#endif
#define Y(NAME_SEGMENT) \
struct TS##NAME_SEGMENT##Deleter { \
void \
operator()(TS##NAME_SEGMENT ptr) \
{ \
TSAssert(TS##NAME_SEGMENT##Destroy(ptr) == TS_SUCCESS); \
} \
}; \
using TS##NAME_SEGMENT##UniqPtr = std::unique_ptr<std::remove_pointer_t<TS##NAME_SEGMENT>, TS##NAME_SEGMENT##Deleter>;
Y(MBuffer)
X(MimeParser)
X(Thread)
X(Mutex)
Y(CacheKey)
X(Cont)
X(SslContext)
X(IOBuffer)
Y(TextLogObject)
X(Uuid)
#undef X
#undef Y
struct TSMemDeleter {
void
operator()(void *ptr)
{
TSfree(ptr);
}
};
using TSMemUniqPtr = std::unique_ptr<void, TSMemDeleter>;
struct TSIOBufferReaderDeleter {
void
operator()(TSIOBufferReader ptr)
{
TSIOBufferReaderFree(ptr);
}
};
using TSIOBufferReaderUniqPtr = std::unique_ptr<std::remove_pointer_t<TSIOBufferReader>, TSIOBufferReaderDeleter>;
class TxnAuxDataMgrBase
{
protected:
struct MgrData_ {
TSCont txnCloseContp = nullptr;
int txnArgIndex = -1;
};
public:
class MgrData : private MgrData_
{
friend class TxnAuxDataMgrBase;
};
protected:
static MgrData_ &
access(MgrData &md)
{
return md;
}
};
using TxnAuxMgrData = TxnAuxDataMgrBase::MgrData;
template <class TxnAuxData, TxnAuxMgrData &MDRef> class TxnAuxDataMgr : private TxnAuxDataMgrBase
{
public:
using Data = TxnAuxData;
static void
init(char const *arg_name, char const *arg_desc = "per-transaction auxiliary data")
{
MgrData_ &md = access(MDRef);
if (md.txnArgIndex >= 0) {
return;
}
TSReleaseAssert(TSUserArgIndexReserve(TS_USER_ARGS_TXN, arg_name, arg_desc, &md.txnArgIndex) == TS_SUCCESS);
TSReleaseAssert(md.txnCloseContp = TSContCreate(_deleteAuxData, nullptr));
}
static TxnAuxData &
data(TSHttpTxn txn)
{
MgrData_ &md = access(MDRef);
TSAssert(md.txnArgIndex >= 0);
auto d = static_cast<TxnAuxData *>(TSUserArgGet(txn, md.txnArgIndex));
if (!d) {
d = new TxnAuxData;
TSUserArgSet(txn, md.txnArgIndex, d);
TSHttpTxnHookAdd(txn, TS_HTTP_TXN_CLOSE_HOOK, md.txnCloseContp);
}
return *d;
}
private:
static int
_deleteAuxData(TSCont, TSEvent, void *edata)
{
MgrData_ &md = access(MDRef);
auto txn = static_cast<TSHttpTxn>(edata);
auto data = static_cast<TxnAuxData *>(TSUserArgGet(txn, md.txnArgIndex));
delete data;
TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
return 0;
};
};
}