erlang's global lock
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

133 linhas
3.5 KiB

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