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.

134 regels
3.6 KiB

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