Coverage Report

Created: 2025-07-01 06:08

/src/logging-log4cxx/src/main/cpp/aprinitializer.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
#include <log4cxx/logstring.h>
18
#if !defined(LOG4CXX)
19
  #define LOG4CXX 1
20
#endif
21
#include <log4cxx/helpers/aprinitializer.h>
22
#include <apr_pools.h>
23
#include <assert.h>
24
#include <log4cxx/helpers/threadspecificdata.h>
25
#include <apr_thread_proc.h>
26
#include <log4cxx/helpers/filewatchdog.h>
27
#include <log4cxx/helpers/date.h>
28
#include <log4cxx/helpers/loglog.h>
29
#include <list>
30
#include <algorithm>
31
32
using namespace LOG4CXX_NS::helpers;
33
using namespace LOG4CXX_NS;
34
35
bool APRInitializer::isDestructed = false;
36
37
using IdentifiedObject = std::pair<size_t, ObjectPtr>;
38
39
struct APRInitializer::APRInitializerPrivate{
40
  APRInitializerPrivate() :
41
0
    p(0),
42
0
    startTime(0),
43
0
    tlsKey(0){
44
45
0
  }
46
  ~APRInitializerPrivate()
47
0
  {
48
    // Delete in reverse order
49
0
    while (!objects.empty())
50
0
      objects.pop_back();
51
0
  }
52
53
  apr_pool_t* p;
54
  std::mutex mutex;
55
  std::list<FileWatchdog*> watchdogs;
56
  log4cxx_time_t startTime;
57
  apr_threadkey_t* tlsKey;
58
  std::vector<IdentifiedObject> objects;
59
};
60
61
namespace
62
{
63
void tlsDestructImpl(void* ptr)
64
0
{
65
0
  delete ((ThreadSpecificData*) ptr);
66
0
}
67
}
68
69
#if LOG4CXX_ABI_VERSION <= 15
70
extern "C" void tlsDestruct(void* ptr)
71
0
{
72
0
  return tlsDestructImpl(ptr);
73
0
}
74
#endif
75
76
namespace
77
{
78
// The first object created and the last object destroyed
79
struct apr_environment
80
{
81
    apr_environment()
82
0
    {
83
0
        apr_initialize();
84
0
    }
85
    ~apr_environment()
86
0
    {
87
0
        apr_terminate();
88
0
    }
89
};
90
91
}
92
93
94
APRInitializer::APRInitializer() :
95
0
  m_priv(std::make_unique<APRInitializerPrivate>())
96
0
{
97
0
  apr_pool_create(&m_priv->p, NULL);
98
0
  m_priv->startTime = Date::currentTime();
99
0
#if APR_HAS_THREADS
100
0
  apr_status_t stat = apr_threadkey_private_create(&m_priv->tlsKey, tlsDestructImpl, m_priv->p);
101
0
  assert(stat == APR_SUCCESS);
102
0
#endif
103
0
}
104
105
APRInitializer::~APRInitializer()
106
0
{
107
0
  stopWatchDogs();
108
0
  isDestructed = true;
109
0
#if APR_HAS_THREADS
110
0
  std::lock_guard<std::mutex> lock(m_priv->mutex);
111
0
  apr_threadkey_private_delete(m_priv->tlsKey);
112
0
#endif
113
0
}
114
115
void APRInitializer::stopWatchDogs()
116
0
{
117
0
  std::lock_guard<std::mutex> lock(m_priv->mutex);
118
119
0
  while (!m_priv->watchdogs.empty())
120
0
  {
121
0
    m_priv->watchdogs.back()->stop();
122
0
    delete m_priv->watchdogs.back();
123
0
    m_priv->watchdogs.pop_back();
124
0
  }
125
0
}
126
127
void APRInitializer::unregisterAll()
128
0
{
129
0
  getInstance().stopWatchDogs();
130
0
}
131
132
APRInitializer& APRInitializer::getInstance()
133
0
{
134
0
  static WideLife<apr_environment> env;
135
0
  static WideLife<APRInitializer> init;
136
0
  return init;
137
0
}
138
139
140
#if LOG4CXX_ABI_VERSION <= 15
141
log4cxx_time_t APRInitializer::initialize()
142
0
{
143
0
  return getInstance().m_priv->startTime;
144
0
}
145
#endif
146
147
log4cxx_time_t APRInitializer::getStartTime()
148
0
{
149
0
  return getInstance().m_priv->startTime;
150
0
}
151
152
apr_pool_t* APRInitializer::getRootPool()
153
0
{
154
0
  return getInstance().m_priv->p;
155
0
}
156
157
apr_threadkey_t* APRInitializer::getTlsKey()
158
0
{
159
0
  return getInstance().m_priv->tlsKey;
160
0
}
161
162
void APRInitializer::registerCleanup(FileWatchdog* watchdog)
163
0
{
164
0
  APRInitializer& instance(getInstance());
165
0
  std::lock_guard<std::mutex> lock(instance.m_priv->mutex);
166
0
  instance.m_priv->watchdogs.push_back(watchdog);
167
0
}
168
169
void APRInitializer::unregisterCleanup(FileWatchdog* watchdog)
170
0
{
171
0
  APRInitializer& instance(getInstance());
172
0
  std::lock_guard<std::mutex> lock(instance.m_priv->mutex);
173
174
0
  auto iter = std::find(instance.m_priv->watchdogs.begin(), instance.m_priv->watchdogs.end(), watchdog);
175
0
  if (iter != instance.m_priv->watchdogs.end())
176
0
    instance.m_priv->watchdogs.erase(iter);
177
0
}
178
179
void APRInitializer::addObject(size_t key, const ObjectPtr& pObject)
180
0
{
181
0
  std::lock_guard<std::mutex> lock(m_priv->mutex);
182
0
  auto pItem = std::find_if(m_priv->objects.begin(), m_priv->objects.end()
183
0
    , [key](const IdentifiedObject& item) { return item.first == key; }
184
0
    );
185
0
  if (m_priv->objects.end() != pItem)
186
0
    pItem->second = pObject;
187
0
  else
188
0
    m_priv->objects.emplace_back(key, pObject);
189
0
}
190
191
const ObjectPtr& APRInitializer::findOrAddObject(size_t key, std::function<ObjectPtr()> creator)
192
0
{
193
0
  std::lock_guard<std::mutex> lock(m_priv->mutex);
194
0
  if (m_priv->objects.empty())
195
0
  {
196
    // Ensure the internal logger has a longer life than other Log4cxx static data
197
0
    LogLog::debug(LOG4CXX_STR("Started"));
198
0
  }
199
0
  auto pItem = std::find_if(m_priv->objects.begin(), m_priv->objects.end()
200
0
    , [key](const IdentifiedObject& item) { return item.first == key; }
201
0
    );
202
0
  if (m_priv->objects.end() != pItem)
203
0
    return pItem->second;
204
0
  m_priv->objects.emplace_back(key, creator());
205
0
  return m_priv->objects.back().second;
206
0
}