blob: a6f11f9add3f9bd369520bd9a8a98b33a84902dd [file]
/*
* 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.
*/
#include <cstring>
#include <cstdlib> // for abort
#include <ts/ts.h> // for debug
// debug messages viewable by setting 'proxy.config.diags.debug.tags'
// in 'records.yaml'
// debug messages during one-time initialization
static const char DEBUG_TAG_INIT[] = "TSContSchedule_test.init";
static const char DEBUG_TAG_SCHD[] = "TSContSchedule_test.schedule";
static const char DEBUG_TAG_HDL[] = "TSContSchedule_test.handler";
static const char DEBUG_TAG_CHK[] = "TSContSchedule_test.check";
static DbgCtl dbg_ctl_init{DEBUG_TAG_INIT};
static DbgCtl dbg_ctl_schd{DEBUG_TAG_SCHD};
static DbgCtl dbg_ctl_hdl{DEBUG_TAG_HDL};
static DbgCtl dbg_ctl_chk{DEBUG_TAG_CHK};
// plugin registration info
static char plugin_name[] = "TSContSchedule_test";
static char vendor_name[] = "apache";
static char support_email[] = "duke8253@apache.org";
static int test_flag = 0;
static TSEventThread thread_1 = nullptr;
static TSEventThread thread_2 = nullptr;
static TSCont contp_1 = nullptr;
static TSCont contp_2 = nullptr;
static int TSContThreadAffinity_handler(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleOnPool_handler_1(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleOnPool_handler_2(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleOnThread_handler_1(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleOnThread_handler_2(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleOnEntirePool_handler(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleEveryOnPool_handler(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleEveryOnThread_handler(TSCont contp, TSEvent event, void *edata);
static int TSContScheduleEveryOnEntirePool_handler(TSCont contp, TSEvent event, void *edata);
static int
TSContThreadAffinity_handler(TSCont contp, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
Dbg(dbg_ctl_hdl, "TSContThreadAffinity handler thread [%p]", TSThreadSelf());
thread_1 = TSEventThreadSelf();
if (TSContThreadAffinityGet(contp) != nullptr) {
Dbg(dbg_ctl_chk, "pass [affinity thread is not null]");
TSContThreadAffinityClear(contp);
if (TSContThreadAffinityGet(contp) == nullptr) {
Dbg(dbg_ctl_chk, "pass [affinity thread is cleared]");
TSContThreadAffinitySet(contp, TSEventThreadSelf());
if (TSContThreadAffinityGet(contp) == thread_1) {
Dbg(dbg_ctl_chk, "pass [affinity thread is set]");
} else {
Dbg(dbg_ctl_chk, "fail [affinity thread is not set]");
}
} else {
Dbg(dbg_ctl_chk, "fail [affinity thread is not cleared]");
}
} else {
Dbg(dbg_ctl_chk, "fail [affinity thread is null]");
}
return 0;
}
void
TSContThreadAffinity_test()
{
TSCont contp = TSContCreate(TSContThreadAffinity_handler, TSMutexCreate());
if (contp == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleOnPool(contp, 0, TS_THREAD_POOL_NET);
}
}
static int
TSContScheduleOnPool_handler_1(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
// This runs on ET_NET threads.
Dbg(dbg_ctl_hdl, "TSContScheduleOnPool handler 1 thread [%p]", TSThreadSelf());
if (thread_1 == nullptr) {
// First time here, record thread id.
thread_1 = TSEventThreadSelf();
} else {
// Second time here, we should be on a different thread since affinity was cleared.
if (thread_1 != TSEventThreadSelf()) {
Dbg(dbg_ctl_chk, "pass [should not be the same thread]");
} else {
Dbg(dbg_ctl_chk, "fail [on the same thread]");
}
}
return 0;
}
static int
TSContScheduleOnPool_handler_2(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
// This runs on ET_TASK threads.
Dbg(dbg_ctl_hdl, "TSContScheduleOnPool handler 2 thread [%p]", TSThreadSelf());
if (thread_2 == nullptr) {
// First time here, record thread id.
thread_2 = TSEventThreadSelf();
} else {
if (thread_2 == TSEventThreadSelf()) {
// Second time there, we should be on the same thread even though affinity was cleared,
// reason being plugin is running on ET_TASK threads, and we were scheduled on ET_TASK
// threads as well, so the thread the plugin is on is used and set to affinity.
Dbg(dbg_ctl_chk, "pass [should be the same thread]");
} else {
Dbg(dbg_ctl_chk, "fail [not the same thread]");
}
}
return 0;
}
void
TSContScheduleOnPool_test()
{
contp_1 = TSContCreate(TSContScheduleOnPool_handler_1, TSMutexCreate());
contp_2 = TSContCreate(TSContScheduleOnPool_handler_2, TSMutexCreate());
if (contp_1 == nullptr || contp_2 == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleOnPool(contp_1, 0, TS_THREAD_POOL_NET);
TSContThreadAffinityClear(contp_1);
TSContScheduleOnPool(contp_1, 100, TS_THREAD_POOL_NET);
TSContScheduleOnPool(contp_2, 200, TS_THREAD_POOL_TASK);
TSContThreadAffinityClear(contp_2);
TSContScheduleOnPool(contp_2, 300, TS_THREAD_POOL_TASK);
}
}
static int
TSContScheduleOnThread_handler_1(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
// Mostly same as TSContScheduleOnPool_handler_1, no need to set affinity
// since we are scheduling directly on to a thread.
Dbg(dbg_ctl_hdl, "TSContScheduleOnThread handler 1 thread [%p]", TSThreadSelf());
if (thread_1 == nullptr) {
thread_1 = TSEventThreadSelf();
Dbg(dbg_ctl_hdl, "[%s] scheduling continuation", plugin_name);
TSContScheduleOnThread(contp_2, 0, thread_1);
TSContScheduleOnThread(contp_2, 0, thread_1);
} else if (thread_2 == nullptr) {
Dbg(dbg_ctl_chk, "fail [schedule delay not applied]");
} else {
if (thread_2 != TSEventThreadSelf()) {
Dbg(dbg_ctl_chk, "pass [should not be the same thread]");
} else {
Dbg(dbg_ctl_chk, "fail [on the same thread]");
}
}
return 0;
}
static int
TSContScheduleOnThread_handler_2(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
Dbg(dbg_ctl_hdl, "TSContScheduleOnThread handler 2 thread [%p]", TSThreadSelf());
if (thread_2 == nullptr) {
thread_2 = TSEventThreadSelf();
} else if (thread_2 == TSEventThreadSelf()) {
Dbg(dbg_ctl_chk, "pass [should be the same thread]");
} else {
Dbg(dbg_ctl_chk, "fail [not the same thread]");
}
return 0;
}
void
TSContScheduleOnThread_test()
{
contp_1 = TSContCreate(TSContScheduleOnThread_handler_1, TSMutexCreate());
contp_2 = TSContCreate(TSContScheduleOnThread_handler_2, TSMutexCreate());
if (contp_1 == nullptr || contp_2 == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleOnPool(contp_1, 0, TS_THREAD_POOL_NET);
TSContThreadAffinityClear(contp_1);
TSContScheduleOnPool(contp_1, 200, TS_THREAD_POOL_NET);
}
}
static int
TSContScheduleOnEntirePool_handler(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
Dbg(dbg_ctl_hdl, "TSContScheduleOnEntirePool handler thread [%p]", TSThreadSelf());
return 0;
}
void
TSContScheduleOnEntirePool_test()
{
TSCont contp = TSContCreate(TSContScheduleOnEntirePool_handler, nullptr);
if (contp == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleOnEntirePool(contp, 0, TS_THREAD_POOL_NET);
}
}
static int
TSContScheduleEveryOnPool_handler(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
Dbg(dbg_ctl_hdl, "TSContScheduleEveryOnPool handler thread [%p]", TSThreadSelf());
if (thread_1 == nullptr) {
// First time here, record thread id.
thread_1 = TSEventThreadSelf();
} else {
// Second time here, we should be on a different thread since affinity was cleared.
if (thread_1 == TSEventThreadSelf()) {
Dbg(dbg_ctl_chk, "pass [should be the same thread]");
} else {
Dbg(dbg_ctl_chk, "fail [not on the same thread]");
}
}
return 0;
}
void
TSContScheduleEveryOnPool_test()
{
TSCont contp = TSContCreate(TSContScheduleEveryOnPool_handler, TSMutexCreate());
if (contp == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleEveryOnPool(contp, 900, TS_THREAD_POOL_NET);
}
}
static int
TSContScheduleEveryOnThread_handler(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
{
Dbg(dbg_ctl_hdl, "TSContScheduleEveryOnThread handler thread [%p]", TSThreadSelf());
if (thread_1 == TSEventThreadSelf()) {
Dbg(dbg_ctl_chk, "pass [should be the same thread]");
} else {
Dbg(dbg_ctl_chk, "fail [not on the same thread]");
}
return 0;
}
void
TSContScheduleEveryOnThread_test()
{
TSCont contp = TSContCreate(TSContScheduleEveryOnThread_handler, TSMutexCreate());
thread_1 = TSEventThreadSelf();
if (contp == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleEveryOnThread(contp, 900, thread_1);
}
}
static int
TSContScheduleEveryOnEntirePool_handler(TSCont /* contp ATS_UNUSED */, TSEvent /* event ATS_UNUSED */,
void * /* edata ATS_UNUSED */)
{
Dbg(dbg_ctl_hdl, "TSContScheduleEveryOnEntirePool handler thread [%p]", TSThreadSelf());
return 0;
}
void
TSContScheduleEveryOnEntirePool_test()
{
TSCont contp = TSContCreate(TSContScheduleEveryOnEntirePool_handler, nullptr);
if (contp == nullptr) {
Dbg(dbg_ctl_schd, "[%s] could not create continuation", plugin_name);
abort();
} else {
Dbg(dbg_ctl_schd, "[%s] scheduling continuation", plugin_name);
TSContScheduleEveryOnEntirePool(contp, 900, TS_THREAD_POOL_NET);
}
}
static int
LifecycleHookTracer(TSCont /* contp ATS_UNUSED */, TSEvent event, void * /* edata ATS_UNUSED */)
{
if (event == TS_EVENT_LIFECYCLE_TASK_THREADS_READY) {
switch (test_flag) {
case 1:
TSContThreadAffinity_test();
break;
case 2:
TSContScheduleOnPool_test();
break;
case 3:
TSContScheduleOnThread_test();
break;
case 4:
TSContScheduleOnEntirePool_test();
break;
case 5:
TSContScheduleEveryOnPool_test();
break;
case 6:
TSContScheduleEveryOnThread_test();
break;
case 7:
TSContScheduleEveryOnEntirePool_test();
break;
default:
break;
}
}
return 0;
}
void
TSPluginInit(int argc, const char *argv[])
{
if (argc == 2) {
int len = strlen(argv[1]);
if (len == 8 && strncmp(argv[1], "affinity", 8) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContThreadAffinity");
test_flag = 1;
} else if (len == 4 && strncmp(argv[1], "pool", 4) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContScheduleOnPool");
test_flag = 2;
} else if (len == 6 && strncmp(argv[1], "thread", 6) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContScheduleOnThread");
test_flag = 3;
} else if (len == 6 && strncmp(argv[1], "entire", 6) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContScheduleOnEntirePool");
test_flag = 4;
} else if (len == 10 && strncmp(argv[1], "every_pool", 10) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContScheduleEveryOnPool");
test_flag = 5;
} else if (len == 12 && strncmp(argv[1], "every_thread", 12) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContScheduleEveryOnThread");
test_flag = 6;
} else if (len == 12 && strncmp(argv[1], "every_entire", 12) == 0) {
Dbg(dbg_ctl_init, "initializing plugin for testing TSContScheduleEveryOnEntirePool");
test_flag = 7;
} else {
goto Lerror;
}
} else {
goto Lerror;
}
TSPluginRegistrationInfo info;
info.plugin_name = plugin_name;
info.vendor_name = vendor_name;
info.support_email = support_email;
if (TSPluginRegister(&info) != TS_SUCCESS) {
Dbg(dbg_ctl_init, "[%s] plugin registration failed", plugin_name);
abort();
}
TSLifecycleHookAdd(TS_LIFECYCLE_TASK_THREADS_READY_HOOK, TSContCreate(LifecycleHookTracer, TSMutexCreate()));
return;
Lerror:
Dbg(dbg_ctl_init, "[%s] plugin invalid argument", plugin_name);
abort();
}