fork.c 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #define REDISMODULE_EXPERIMENTAL_API
  2. /* define macros for having usleep */
  3. #define _BSD_SOURCE
  4. #define _DEFAULT_SOURCE
  5. #include "redismodule.h"
  6. #include <string.h>
  7. #include <assert.h>
  8. #include <unistd.h>
  9. #define UNUSED(V) ((void) V)
  10. int child_pid = -1;
  11. int exitted_with_code = -1;
  12. void done_handler(int exitcode, int bysignal, void *user_data) {
  13. child_pid = -1;
  14. exitted_with_code = exitcode;
  15. assert(user_data==(void*)0xdeadbeef);
  16. UNUSED(bysignal);
  17. }
  18. int fork_create(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  19. {
  20. long long code_to_exit_with;
  21. if (argc != 2) {
  22. RedisModule_WrongArity(ctx);
  23. return REDISMODULE_OK;
  24. }
  25. if(!RMAPI_FUNC_SUPPORTED(RedisModule_Fork)){
  26. RedisModule_ReplyWithError(ctx, "Fork api is not supported in the current redis version");
  27. return REDISMODULE_OK;
  28. }
  29. RedisModule_StringToLongLong(argv[1], &code_to_exit_with);
  30. exitted_with_code = -1;
  31. child_pid = RedisModule_Fork(done_handler, (void*)0xdeadbeef);
  32. if (child_pid < 0) {
  33. RedisModule_ReplyWithError(ctx, "Fork failed");
  34. return REDISMODULE_OK;
  35. } else if (child_pid > 0) {
  36. /* parent */
  37. RedisModule_ReplyWithLongLong(ctx, child_pid);
  38. return REDISMODULE_OK;
  39. }
  40. /* child */
  41. RedisModule_Log(ctx, "notice", "fork child started");
  42. usleep(500000);
  43. RedisModule_Log(ctx, "notice", "fork child exiting");
  44. RedisModule_ExitFromChild(code_to_exit_with);
  45. /* unreachable */
  46. return 0;
  47. }
  48. int fork_exitcode(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  49. {
  50. UNUSED(argv);
  51. UNUSED(argc);
  52. RedisModule_ReplyWithLongLong(ctx, exitted_with_code);
  53. return REDISMODULE_OK;
  54. }
  55. int fork_kill(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  56. {
  57. UNUSED(argv);
  58. UNUSED(argc);
  59. if (RedisModule_KillForkChild(child_pid) != REDISMODULE_OK)
  60. RedisModule_ReplyWithError(ctx, "KillForkChild failed");
  61. else
  62. RedisModule_ReplyWithLongLong(ctx, 1);
  63. child_pid = -1;
  64. return REDISMODULE_OK;
  65. }
  66. int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  67. UNUSED(argv);
  68. UNUSED(argc);
  69. if (RedisModule_Init(ctx,"fork",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
  70. return REDISMODULE_ERR;
  71. if (RedisModule_CreateCommand(ctx,"fork.create", fork_create,"",0,0,0) == REDISMODULE_ERR)
  72. return REDISMODULE_ERR;
  73. if (RedisModule_CreateCommand(ctx,"fork.exitcode", fork_exitcode,"",0,0,0) == REDISMODULE_ERR)
  74. return REDISMODULE_ERR;
  75. if (RedisModule_CreateCommand(ctx,"fork.kill", fork_kill,"",0,0,0) == REDISMODULE_ERR)
  76. return REDISMODULE_ERR;
  77. return REDISMODULE_OK;
  78. }