RM_ThreadSafeContextTryLock a non-blocking method for acquiring GIL (#7738)
Co-authored-by: Yossi Gottlieb <yossigo@gmail.com>
Co-authored-by: Oran Agra <oran@redislabs.com>
(cherry picked from commit 042189fd87)
This commit is contained in:
@@ -23,7 +23,9 @@ TEST_MODULES = \
|
||||
scan.so \
|
||||
datatype.so \
|
||||
auth.so \
|
||||
keyspace_events.so
|
||||
keyspace_events.so \
|
||||
blockedclient.so
|
||||
|
||||
|
||||
.PHONY: all
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#define REDISMODULE_EXPERIMENTAL_API
|
||||
#include "redismodule.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define UNUSED(V) ((void) V)
|
||||
|
||||
void *sub_worker(void *arg) {
|
||||
// Get Redis module context
|
||||
RedisModuleCtx *ctx = (RedisModuleCtx *)arg;
|
||||
|
||||
// Try acquiring GIL
|
||||
int res = RedisModule_ThreadSafeContextTryLock(ctx);
|
||||
|
||||
// GIL is already taken by the calling thread expecting to fail.
|
||||
assert(res != REDISMODULE_OK);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *worker(void *arg) {
|
||||
// Retrieve blocked client
|
||||
RedisModuleBlockedClient *bc = (RedisModuleBlockedClient *)arg;
|
||||
|
||||
// Get Redis module context
|
||||
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(bc);
|
||||
|
||||
// Acquire GIL
|
||||
RedisModule_ThreadSafeContextLock(ctx);
|
||||
|
||||
// Create another thread which will try to acquire the GIL
|
||||
pthread_t tid;
|
||||
int res = pthread_create(&tid, NULL, sub_worker, ctx);
|
||||
assert(res == 0);
|
||||
|
||||
// Wait for thread
|
||||
pthread_join(tid, NULL);
|
||||
|
||||
// Release GIL
|
||||
RedisModule_ThreadSafeContextUnlock(ctx);
|
||||
|
||||
// Reply to client
|
||||
RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||
|
||||
// Unblock client
|
||||
RedisModule_UnblockClient(bc, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int acquire_gil(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
UNUSED(argv);
|
||||
UNUSED(argc);
|
||||
|
||||
/* This command handler tries to acquire the GIL twice
|
||||
* once in the worker thread using "RedisModule_ThreadSafeContextLock"
|
||||
* second in the sub-worker thread
|
||||
* using "RedisModule_ThreadSafeContextTryLock"
|
||||
* as the GIL is already locked. */
|
||||
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0);
|
||||
|
||||
pthread_t tid;
|
||||
int res = pthread_create(&tid, NULL, worker, bc);
|
||||
assert(res == 0);
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
REDISMODULE_NOT_USED(argv);
|
||||
REDISMODULE_NOT_USED(argc);
|
||||
|
||||
if (RedisModule_Init(ctx, "blockedclient", 1, REDISMODULE_APIVER_1)== REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, "acquire_gil", acquire_gil, "", 0, 0, 0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# source tests/support/util.tcl
|
||||
|
||||
set testmodule [file normalize tests/modules/blockedclient.so]
|
||||
|
||||
start_server {tags {"modules"}} {
|
||||
r module load $testmodule
|
||||
|
||||
test {Locked GIL acquisition} {
|
||||
assert_match "OK" [r acquire_gil]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user