2 * Copyright (C) 2017 Cisco Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // @author Changxue Deng <chadeng@cisco.com>
21 #include "lock_free.h"
22 #include "mabain_consts.h"
24 #include "integer_4b_5b.h"
39 void LockFree::LockFreeInit(LockFreeShmData *lock_free_ptr, IndexHeader *hdr, int mode)
41 shm_data_ptr = lock_free_ptr;
43 if(mode & CONSTS::ACCESS_MODE_WRITER)
45 // Clear the lock free data
46 shm_data_ptr->counter.store(0, MEMORY_ORDER_WRITER);
47 shm_data_ptr->offset.store(MAX_6B_OFFSET, MEMORY_ORDER_WRITER);
51 //////////////////////////////////////////////////
52 // DO NOT CHANGE THE STORE ORDER IN THIS FUNCTION.
53 //////////////////////////////////////////////////
54 void LockFree::WriterLockFreeStop()
56 int index = shm_data_ptr->counter % MAX_OFFSET_CACHE;
57 shm_data_ptr->offset_cache[index].store(shm_data_ptr->offset, MEMORY_ORDER_WRITER);
59 shm_data_ptr->counter.fetch_add(1, MEMORY_ORDER_WRITER);
60 shm_data_ptr->offset.store(MAX_6B_OFFSET, MEMORY_ORDER_WRITER);
63 //////////////////////////////////////////////////
64 // DO NOT CHANGE THE LOAD ORDER IN THIS FUNCTION.
65 //////////////////////////////////////////////////
66 int LockFree::ReaderLockFreeStop(const LockFreeData &snapshot, size_t reader_offset,
70 curr.offset = shm_data_ptr->offset.load(MEMORY_ORDER_READER);
71 curr.counter = shm_data_ptr->counter.load(MEMORY_ORDER_READER);
73 if(curr.offset == reader_offset)
75 if(mbdata.options & CONSTS::OPTION_READ_SAVED_EDGE)
77 if(reader_offset == mbdata.edge_ptrs.offset)
79 mbdata.options &= ~CONSTS::OPTION_READ_SAVED_EDGE;
80 return MBError::SUCCESS;
85 mbdata.options |= CONSTS::OPTION_READ_SAVED_EDGE;
89 switch(header->excep_updating_status)
91 case EXCEP_STATUS_ADD_EDGE:
92 case EXCEP_STATUS_ADD_DATA_OFF:
93 case EXCEP_STATUS_ADD_NODE:
94 case EXCEP_STATUS_REMOVE_EDGE:
95 case EXCEP_STATUS_RC_NODE:
96 case EXCEP_STATUS_RC_EDGE_STR:
97 case EXCEP_STATUS_RC_DATA:
98 memcpy(mbdata.edge_ptrs.edge_buff, header->excep_buff, EDGE_SIZE);
99 mbdata.edge_ptrs.offset = shm_data_ptr->offset.load(MEMORY_ORDER_READER);
101 case EXCEP_STATUS_CLEAR_EDGE:
103 memset(mbdata.edge_ptrs.edge_buff, 0, EDGE_SIZE);
104 mbdata.edge_ptrs.offset = shm_data_ptr->offset.load(MEMORY_ORDER_READER);
107 if(mbdata.edge_ptrs.offset == reader_offset)
109 InitTempEdgePtrs(mbdata.edge_ptrs);
113 mbdata.options &= ~CONSTS::OPTION_READ_SAVED_EDGE;
114 mbdata.edge_ptrs.offset = MAX_6B_OFFSET;
116 return MBError::TRY_AGAIN;
119 if(mbdata.options & CONSTS::OPTION_READ_SAVED_EDGE)
120 mbdata.options &= ~CONSTS::OPTION_READ_SAVED_EDGE;
122 // Note it is expected that count_diff can overflow.
123 uint32_t count_diff = curr.counter - snapshot.counter;
125 return MBError::SUCCESS; // Writer was doing nothing. Reader can proceed.
126 if(count_diff >= MAX_OFFSET_CACHE)
127 return MBError::TRY_AGAIN; // Cache is overwritten. Have to retry.
129 for(unsigned i = 0; i < count_diff; i++)
131 int index = (snapshot.counter + i) % MAX_OFFSET_CACHE;
132 if(reader_offset == shm_data_ptr->offset_cache[index].load(MEMORY_ORDER_READER))
133 return MBError::TRY_AGAIN;
136 // Need to recheck the counter difference
137 count_diff = shm_data_ptr->counter.load(MEMORY_ORDER_READER) - snapshot.counter;
138 if(count_diff >= MAX_OFFSET_CACHE)
139 return MBError::TRY_AGAIN;
141 // Writer was modifying different edges. It is safe to for the reader to proceed.
142 return MBError::SUCCESS;