Skip to content

Commit ffe0c19

Browse files
zouyuSolidWallOfCode
authored andcommitted
TS-3235: fix crash problem caused by sync problem in PluginVC.
This closes apache#164.
1 parent 2a0a86c commit ffe0c19

File tree

5 files changed

+81
-34
lines changed

5 files changed

+81
-34
lines changed

lib/atscppapi/src/InterceptPlugin.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void destroyCont(InterceptPlugin::State *state);
112112

113113
InterceptPlugin::InterceptPlugin(Transaction &transaction, InterceptPlugin::Type type) : TransactionPlugin(transaction)
114114
{
115-
TSCont cont = TSContCreate(handleEvents, TSMutexCreate());
115+
TSCont cont = TSContCreate(handleEvents, NULL);
116116
state_ = new State(cont, this);
117117
TSContDataSet(cont, state_);
118118
TSHttpTxn txn = static_cast<TSHttpTxn>(transaction.getAtsHandle());
@@ -137,6 +137,7 @@ InterceptPlugin::~InterceptPlugin()
137137
bool
138138
InterceptPlugin::produce(const void *data, int data_size)
139139
{
140+
ScopedSharedMutexLock lock(getMutex());
140141
if (!state_->net_vc_) {
141142
LOG_ERROR("Intercept not operational");
142143
return false;

lib/atscppapi/src/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ libatscppapi_la_SOURCES = GlobalPlugin.cc \
4848
GzipDeflateTransformation.cc \
4949
GzipInflateTransformation.cc \
5050
AsyncTimer.cc \
51-
InterceptPlugin.cc
51+
InterceptPlugin.cc \
52+
Mutex.cc
5253

5354
library_includedir=$(includedir)/atscppapi
5455
base_include_folder = $(top_srcdir)/$(subdir)/include/atscppapi

lib/atscppapi/src/Mutex.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
/**
20+
* @file Mutex.cc
21+
*/
22+
23+
#include "atscppapi/Mutex.h"
24+
25+
#include <ts/ts.h>
26+
27+
atscppapi::ScopedContinuationLock::ScopedContinuationLock(TSCont contp) : mutex_(TSContMutexGet(contp))
28+
{
29+
TSMutexLock(mutex_);
30+
}
31+
atscppapi::ScopedContinuationLock::~ScopedContinuationLock()
32+
{
33+
TSMutexUnlock(mutex_);
34+
}

lib/atscppapi/src/include/atscppapi/Mutex.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
#include <atscppapi/noncopyable.h>
3030
#include <atscppapi/shared_ptr.h>
3131

32+
// Import in name only.
33+
typedef struct tsapi_mutex *TSMutex;
34+
typedef struct tsapi_cont *TSCont;
35+
3236
namespace atscppapi
3337
{
3438
/**
@@ -252,6 +256,30 @@ class ScopedSharedMutexTryLock : noncopyable
252256
bool has_lock_;
253257
};
254258

259+
/**
260+
* @brief Lock a TS Continuation by acquiring and releasing its lock in the current scope.
261+
*
262+
* This is an RAII implementation which will lock a mutex for the continuation at the declaration of an instance
263+
* and unlock it when the instance goes out of scope.
264+
*/
265+
class ScopedContinuationLock : noncopyable
266+
{
267+
public:
268+
/**
269+
* Create the scoped mutex lock, once this object is constructed the lock will be held by the thread.
270+
* @param cont The TS continuation.
271+
*/
272+
explicit ScopedContinuationLock(TSCont contp);
273+
274+
/**
275+
* Unlock the mutex.
276+
*/
277+
~ScopedContinuationLock();
278+
279+
private:
280+
TSMutex mutex_;
281+
};
282+
255283
} /* atscppapi */
256284

257285

proxy/PluginVC.cc

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,9 @@ PluginVC::reenable(VIO *vio)
293293
{
294294
ink_assert(!closed);
295295
ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE);
296-
ink_assert(vio->mutex->thread_holding == this_ethread());
296+
297+
Ptr<ProxyMutex> sm_mutex = vio->mutex;
298+
SCOPED_MUTEX_LOCK(lock, sm_mutex, this_ethread());
297299

298300
Debug("pvc", "[%u] %s: reenable %s", core_obj->id, PVC_TYPE, (vio->op == VIO::WRITE) ? "Write" : "Read");
299301

@@ -313,34 +315,26 @@ PluginVC::reenable_re(VIO *vio)
313315
{
314316
ink_assert(!closed);
315317
ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE);
316-
ink_assert(vio->mutex->thread_holding == this_ethread());
317318

318319
Debug("pvc", "[%u] %s: reenable_re %s", core_obj->id, PVC_TYPE, (vio->op == VIO::WRITE) ? "Write" : "Read");
319320

320-
MUTEX_TRY_LOCK(lock, this->mutex, this_ethread());
321-
if (!lock.is_locked()) {
322-
if (vio->op == VIO::WRITE) {
323-
need_write_process = true;
324-
} else {
325-
need_read_process = true;
326-
}
327-
setup_event_cb(PVC_LOCK_RETRY_TIME, &sm_lock_retry_event);
328-
return;
329-
}
321+
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
330322

331-
reentrancy_count++;
323+
++reentrancy_count;
332324

333325
if (vio->op == VIO::WRITE) {
334326
ink_assert(vio == &write_state.vio);
327+
need_write_process = true;
335328
process_write_side(false);
336329
} else if (vio->op == VIO::READ) {
337330
ink_assert(vio == &read_state.vio);
331+
need_read_process = true;
338332
process_read_side(false);
339333
} else {
340334
ink_release_assert(0);
341335
}
342336

343-
reentrancy_count--;
337+
--reentrancy_count;
344338

345339
// To process the close, we need the lock
346340
// for the PluginVC. Schedule an event
@@ -353,31 +347,20 @@ PluginVC::reenable_re(VIO *vio)
353347
void
354348
PluginVC::do_io_close(int /* flag ATS_UNUSED */)
355349
{
356-
ink_assert(closed == false);
350+
ink_assert(!closed);
357351
ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE);
358352

359353
Debug("pvc", "[%u] %s: do_io_close", core_obj->id, PVC_TYPE);
360354

361-
if (reentrancy_count > 0) {
362-
// Do nothing since dealloacting ourselves
363-
// now will lead to us running on a dead
364-
// PluginVC since we are being called
365-
// reentrantly
355+
SCOPED_MUTEX_LOCK(lock, mutex, this_ethread());
356+
if (!closed) { // if already closed, need to do nothing.
366357
closed = true;
367-
return;
368-
}
369358

370-
MUTEX_TRY_LOCK(lock, mutex, this_ethread());
371-
372-
if (!lock.is_locked()) {
373-
setup_event_cb(PVC_LOCK_RETRY_TIME, &sm_lock_retry_event);
374-
closed = true;
375-
return;
376-
} else {
377-
closed = true;
359+
// If re-entered then that earlier handler will clean up, otherwise set up a ping
360+
// to drive that process (too dangerous to do it here).
361+
if (reentrancy_count <= 0)
362+
setup_event_cb(0, &sm_lock_retry_event);
378363
}
379-
380-
process_close();
381364
}
382365

383366
void

0 commit comments

Comments
 (0)