|
15 | 15 |
|
16 | 16 | using namespace dmq; |
17 | 17 |
|
| 18 | +// --------------------------------------------------------------------------- |
| 19 | +// Reference-counted curl global init/cleanup — safe for multiple AsyncHttp |
| 20 | +// instances in the same process. |
| 21 | +// --------------------------------------------------------------------------- |
| 22 | +static std::mutex g_curlMutex; |
| 23 | +static int g_curlRefCount = 0; |
| 24 | + |
| 25 | +static int curl_global_addref() |
| 26 | +{ |
| 27 | + std::lock_guard<std::mutex> lock(g_curlMutex); |
| 28 | + if (g_curlRefCount == 0) { |
| 29 | + CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT); |
| 30 | + if (res != CURLE_OK) return static_cast<int>(res); |
| 31 | + } |
| 32 | + ++g_curlRefCount; |
| 33 | + return 0; |
| 34 | +} |
| 35 | + |
| 36 | +static void curl_global_release() |
| 37 | +{ |
| 38 | + std::lock_guard<std::mutex> lock(g_curlMutex); |
| 39 | + if (g_curlRefCount > 0 && --g_curlRefCount == 0) |
| 40 | + curl_global_cleanup(); |
| 41 | +} |
| 42 | + |
18 | 43 | namespace async { |
19 | 44 |
|
20 | 45 | // ----------------------------------------------------------------------- |
@@ -64,7 +89,7 @@ namespace async { |
64 | 89 |
|
65 | 90 | AsyncHttp::~AsyncHttp() |
66 | 91 | { |
67 | | - if (m_curl || m_thread.GetThreadId() != std::thread::id()) |
| 92 | + if (m_running) |
68 | 93 | shutdown(); |
69 | 94 | } |
70 | 95 |
|
@@ -180,27 +205,29 @@ namespace async { |
180 | 205 |
|
181 | 206 | int AsyncHttp::init() |
182 | 207 | { |
183 | | - if (m_curl) return 0; // already initialized |
| 208 | + if (m_running) return 0; // already initialized |
184 | 209 |
|
185 | | - CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT); |
186 | | - if (res != CURLE_OK) return static_cast<int>(res); |
| 210 | + int res = curl_global_addref(); |
| 211 | + if (res != 0) return res; |
187 | 212 |
|
188 | 213 | m_curl = curl_easy_init(); |
189 | 214 | if (!m_curl) return -1; |
190 | 215 |
|
191 | 216 | m_thread.CreateThread(); |
| 217 | + m_running = true; |
192 | 218 | return 0; |
193 | 219 | } |
194 | 220 |
|
195 | 221 | int AsyncHttp::shutdown(dmq::Duration timeout) |
196 | 222 | { |
197 | | - if (m_thread.GetThreadId() != std::thread::id()) { |
| 223 | + if (m_running) { |
198 | 224 | auto fn = std::function<void()>([this]() { HttpCleanup(); }); |
199 | 225 | auto delegate = MakeDelegate(fn, m_thread, timeout); |
200 | 226 | delegate.AsyncInvoke(); |
201 | 227 | m_thread.ExitThread(); |
| 228 | + m_running = false; |
202 | 229 | } |
203 | | - curl_global_cleanup(); |
| 230 | + curl_global_release(); |
204 | 231 | return 0; |
205 | 232 | } |
206 | 233 |
|
|
0 commit comments