erlang's global lock
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
3.5 KiB

1 year ago
1 year ago
1 year ago
  1. #include "erl_nif.h"
  2. #include <atomic>
  3. using namespace std;
  4. const int LockSize = 2097152;
  5. atomic<uint64_t> LockSlot[LockSize];
  6. ERL_NIF_TERM atomTrue;
  7. ERL_NIF_TERM atomFalse;
  8. ERL_NIF_TERM atomUndefined;
  9. int nifLoad(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM){
  10. atomTrue = enif_make_atom(env, "true");
  11. atomFalse = enif_make_atom(env, "false");
  12. atomUndefined = enif_make_atom(env, "undefined");
  13. return 0;
  14. }
  15. bool lockOne(ErlNifEnv *env, ErlNifPid *ThePid, int KeyIx, uint64_t Val){
  16. uint64_t Expected = 0;
  17. if (LockSlot[KeyIx].compare_exchange_strong(Expected, Val)){
  18. return true;
  19. }else{
  20. ThePid->pid = (ERL_NIF_TERM)Expected;
  21. if (enif_is_process_alive(env, ThePid)){
  22. return false;
  23. }else{
  24. if (LockSlot[KeyIx].compare_exchange_strong(Expected, Val)){
  25. return true;
  26. }else{
  27. return false;
  28. }
  29. }
  30. }
  31. }
  32. ERL_NIF_TERM tryLock(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){
  33. int KeyIx;
  34. enif_get_int(env, argv[0], &KeyIx);
  35. ErlNifPid ThePid;
  36. enif_self(env, &ThePid);
  37. uint64_t Val = (uint64_t)(ThePid.pid);
  38. if (lockOne(env, &ThePid, KeyIx, Val)){
  39. return atomTrue;
  40. }else{
  41. return atomFalse;
  42. }
  43. }
  44. ERL_NIF_TERM tryLocks(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){
  45. ERL_NIF_TERM allList = argv[0];
  46. ERL_NIF_TERM head;
  47. ErlNifPid ThePid;
  48. enif_self(env, &ThePid);
  49. uint64_t Val = (uint64_t)(ThePid.pid);
  50. int KeyIx;
  51. int cnt = -1;
  52. while (enif_get_list_cell(env, allList, &head, &allList)){
  53. enif_get_int(env, head, &KeyIx);
  54. if(lockOne(env, &ThePid, KeyIx, Val)){
  55. cnt++;
  56. }else{
  57. allList = argv[0];
  58. for(int i = 0; i <= cnt; i++){
  59. enif_get_list_cell(env, allList, &head, &allList);
  60. enif_get_int(env, head, &KeyIx);
  61. LockSlot[KeyIx].store(0);
  62. }
  63. return atomFalse;
  64. }
  65. }
  66. return atomTrue;
  67. }
  68. ERL_NIF_TERM releaseLock(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){
  69. int KeyIx;
  70. enif_get_int(env, argv[0], &KeyIx);
  71. ErlNifPid ThePid;
  72. enif_self(env, &ThePid);
  73. uint64_t Expected = (uint64_t)(ThePid.pid);
  74. if (LockSlot[KeyIx].compare_exchange_strong(Expected, 0)){
  75. return atomTrue;
  76. }else{
  77. return atomFalse;
  78. }
  79. }
  80. ERL_NIF_TERM releaseLocks(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){
  81. ERL_NIF_TERM allList = argv[0];
  82. ERL_NIF_TERM head;
  83. ErlNifPid ThePid;
  84. enif_self(env, &ThePid);
  85. uint64_t Expected = (uint64_t)(ThePid.pid);
  86. uint64_t RExpected;
  87. int KeyIx;
  88. int isAllOk = 1;
  89. while (enif_get_list_cell(env, allList, &head, &allList)){
  90. enif_get_int(env, head, &KeyIx);
  91. RExpected = Expected;
  92. if (!LockSlot[KeyIx].compare_exchange_strong(RExpected, 0)){
  93. isAllOk = 0;
  94. }
  95. }
  96. return isAllOk > 0 ? atomTrue : atomFalse;
  97. }
  98. ERL_NIF_TERM getLockPid(ErlNifEnv *env, int, const ERL_NIF_TERM argv[]){
  99. int KeyIx;
  100. enif_get_int(env, argv[0], &KeyIx);
  101. ErlNifPid ThePid;
  102. uint64_t Var = LockSlot[KeyIx].load();
  103. if (Var > 0){
  104. ThePid.pid = (ERL_NIF_TERM)Var;
  105. return enif_make_pid(env, &ThePid);
  106. }else{
  107. return atomUndefined;
  108. }
  109. }
  110. static ErlNifFunc nifFuncs[] = {
  111. {"tryLock", 1, tryLock},
  112. {"tryLocks", 1, tryLocks},
  113. {"releaseLock", 1, releaseLock},
  114. {"releaseLocks", 1, releaseLocks},
  115. {"getLockPid", 1, getLockPid}
  116. };
  117. ERL_NIF_INIT(eNifLock, nifFuncs, &nifLoad, NULL, NULL, NULL)