tlockfree.c 3.1 KB
Newer Older
H
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

S
Shengliang Guan 已提交
16
#define _DEFAULT_SOURCE
B
Bomin Zhang 已提交
17
#include "tlockfree.h"
H
Hongze Cheng 已提交
18 19

#define TD_RWLATCH_WRITE_FLAG 0x40000000
D
dapan1121 已提交
20
#define TD_RWLATCH_REENTRANT_FLAG 0x4000000000000000
H
Hongze Cheng 已提交
21 22

void taosInitRWLatch(SRWLatch *pLatch) { *pLatch = 0; }
23
void taosInitReentrantRWLatch(SRWLatch *pLatch) { *pLatch = TD_RWLATCH_REENTRANT_FLAG; }
H
Hongze Cheng 已提交
24 25 26

void taosWLockLatch(SRWLatch *pLatch) {
  SRWLatch oLatch, nLatch;
S
Shengliang Guan 已提交
27
  int32_t  nLoops = 0;
H
Hongze Cheng 已提交
28 29 30

  // Set write flag
  while (1) {
31
    oLatch = atomic_load_64(pLatch);
H
Hongze Cheng 已提交
32
    if (oLatch & TD_RWLATCH_WRITE_FLAG) {
33 34 35 36 37 38
      if (oLatch & TD_RWLATCH_REENTRANT_FLAG) {
        nLatch = (((oLatch >> 32) + 1) << 32) | (oLatch & 0xFFFFFFFF);
        if (atomic_val_compare_exchange_64(pLatch, oLatch, nLatch) == oLatch) break;

        continue;
      }
H
Hongze Cheng 已提交
39 40 41 42 43 44 45 46 47
      nLoops++;
      if (nLoops > 1000) {
        sched_yield();
        nLoops = 0;
      }
      continue;
    }

    nLatch = oLatch | TD_RWLATCH_WRITE_FLAG;
48
    if (atomic_val_compare_exchange_64(pLatch, oLatch, nLatch) == oLatch) break;
H
Hongze Cheng 已提交
49 50 51 52 53
  }

  // wait for all reads end
  nLoops = 0;
  while (1) {
54 55
    oLatch = atomic_load_64(pLatch);
    if (0 == (oLatch & 0xFFFFFFF)) break;
H
Hongze Cheng 已提交
56 57 58 59 60 61 62 63
    nLoops++;
    if (nLoops > 1000) {
      sched_yield();
      nLoops = 0;
    }
  }
}

64
// no reentrant
D
dapan1121 已提交
65 66
int32_t taosWTryLockLatch(SRWLatch *pLatch) {
  SRWLatch oLatch, nLatch;
67 68
  oLatch = atomic_load_64(pLatch);
  if (oLatch << 2) {
D
dapan1121 已提交
69 70 71 72
    return -1;
  }

  nLatch = oLatch | TD_RWLATCH_WRITE_FLAG;
73
  if (atomic_val_compare_exchange_64(pLatch, oLatch, nLatch) == oLatch) {
D
dapan1121 已提交
74 75 76 77 78 79
    return 0;
  }

  return -1;
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
void taosWUnLockLatch(SRWLatch *pLatch) { 
  SRWLatch oLatch, nLatch, wLatch;

  while (1) {  
    oLatch = atomic_load_64(pLatch);
    
    if (0 == (oLatch & TD_RWLATCH_REENTRANT_FLAG)) {
      atomic_store_64(pLatch, 0); 
      break;
    }

    wLatch = ((oLatch << 2) >> 34);
    if (wLatch) {
      nLatch = ((--wLatch) << 32) | TD_RWLATCH_REENTRANT_FLAG | TD_RWLATCH_WRITE_FLAG;
    } else {
      nLatch = TD_RWLATCH_REENTRANT_FLAG;
    }

    if (atomic_val_compare_exchange_64(pLatch, oLatch, nLatch) == oLatch) break;
  }
}
H
Hongze Cheng 已提交
101 102 103

void taosRLockLatch(SRWLatch *pLatch) {
  SRWLatch oLatch, nLatch;
S
Shengliang Guan 已提交
104
  int32_t  nLoops = 0;
H
Hongze Cheng 已提交
105 106

  while (1) {
107
    oLatch = atomic_load_64(pLatch);
H
Hongze Cheng 已提交
108 109 110 111 112 113 114 115 116 117
    if (oLatch & TD_RWLATCH_WRITE_FLAG) {
      nLoops++;
      if (nLoops > 1000) {
        sched_yield();
        nLoops = 0;
      }
      continue;
    }

    nLatch = oLatch + 1;
118
    if (atomic_val_compare_exchange_64(pLatch, oLatch, nLatch) == oLatch) break;
H
Hongze Cheng 已提交
119 120 121
  }
}

122
void taosRUnLockLatch(SRWLatch *pLatch) { atomic_fetch_sub_64(pLatch, 1); }