File: Cleanup.h

package info (click to toggle)
trafficserver 9.2.5%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 53,008 kB
  • sloc: cpp: 345,484; ansic: 31,134; python: 24,200; sh: 7,271; makefile: 3,045; perl: 2,261; java: 277; pascal: 119; sql: 94; xml: 2
file content (186 lines) | stat: -rw-r--r-- 6,055 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/**
  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
{
// For TS API types TSXxx with a TSXxxDestroy function, define standard deleter TSXxxDeleter, and use it to
// define TSXxxUniqPtr (specialization of std::unique_ptr).  X() is used when the destroy function returns void,
// Y() is used when the destroy function returns TSReturnCode.

#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)       // Defines TSMBufferDeleter and TSMBufferUniqPtr.
X(MimeParser)    // Defines TSMimeParserDeleter and TSMimeParserUniqPtr.
X(Thread)        // Defines TSThreadDeleter and TSThreadUniqPtr.
X(Mutex)         // Defines TSMutexDeleter and TSMutexUniqPtr.
Y(CacheKey)      // Defines TSCacheKeyDeleter and TSCacheKeyUniqPtr.
X(Cont)          // Defines TSContDeleter and TSContUniqPtr.
X(SslContext)    // Defines TSSslContextDeleter and TSSslContextUniqPtr.
X(IOBuffer)      // Defines TSIOBufferDeleter and TSIOBufferUniqPtr.
Y(TextLogObject) // Defines TSTextLogObjectDeleter and TSTextLogObjectUniqPtr.
X(Uuid)          // Defines TSUuidDeleter and TSUuidUniqPtr.

#undef X
#undef Y

// Deleter and unique pointer for memory buffer returned by TSalloc(), TSrealloc(), Tstrdup(), TSsrtndup().
//
struct TSMemDeleter {
  void
  operator()(void *ptr)
  {
    TSfree(ptr);
  }
};
using TSMemUniqPtr = std::unique_ptr<void, TSMemDeleter>;

// Deleter and unique pointer for TSIOBufferReader.  Care must be taken that the reader is deleted before the
// TSIOBuffer to which it refers is deleted.
//
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;

// Class to manage auxiliary data for a transaction.  If an instance is created for the transaction, the instance
// will be deleted on the TXN_CLOSE transaction hook (which is always triggered for all transactions).
// The TxnAuxData class must have a public default constructor.
//
template <class TxnAuxData, TxnAuxMgrData &MDRef> class TxnAuxDataMgr : private TxnAuxDataMgrBase
{
public:
  using Data = TxnAuxData;

  // This must be called from the plugin init function.  arg_name is the name for the transaction argument used
  // to store the pointer to the auxiliary data class instance.  Repeated calls are ignored.
  //
  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));
  }

  // Get a reference to the auxiliary data for a transaction.
  //
  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;
  };
};

} // end namespace atscppapi