Changeset 24020
- Timestamp:
- 02/19/08 14:16:36 (9 months ago)
- Files:
-
- 1 modified
-
haiku/trunk/src/system/kernel/fs/vfs.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
haiku/trunk/src/system/kernel/fs/vfs.cpp
r23983 r24020 122 122 }; 123 123 124 struct advisory_lock : public DoublyLinkedListLinkImpl<advisory_lock> { 125 list_link link; 126 team_id team; 127 pid_t session; 128 off_t start; 129 off_t end; 130 bool shared; 131 }; 132 133 typedef DoublyLinkedList<advisory_lock> LockList; 134 124 135 struct advisory_locking { 125 136 sem_id lock; 126 137 sem_id wait_sem; 127 struct list locks; 128 }; 129 130 struct advisory_lock { 131 list_link link; 132 team_id team; 133 pid_t session; 134 off_t offset; 135 off_t length; 136 bool shared; 138 LockList locks; 137 139 }; 138 140 … … 1048 1050 return B_FILE_ERROR; 1049 1051 1050 struct advisory_locking *locking = (struct advisory_locking *)malloc( 1051 sizeof(struct advisory_locking)); 1052 struct advisory_locking *locking = new(std::nothrow) advisory_locking; 1052 1053 if (locking == NULL) 1053 1054 return B_NO_MEMORY; … … 1067 1068 } 1068 1069 1069 list_init(&locking->locks);1070 1071 1070 // We need to set the locking structure atomically - someone 1072 1071 // else might set one at the same time 1073 1072 do { 1074 if (atomic_test_and_set((vint32 *)&vnode->advisory_locking, (addr_t)locking,1075 NULL) == NULL)1073 if (atomic_test_and_set((vint32 *)&vnode->advisory_locking, 1074 (addr_t)locking, NULL) == NULL) 1076 1075 return B_OK; 1077 1076 } while (get_advisory_locking(vnode) == NULL); … … 1085 1084 delete_sem(locking->wait_sem); 1086 1085 err1: 1087 free(locking);1086 delete locking; 1088 1087 return status; 1089 1088 } … … 1103 1102 status_t status = B_BAD_VALUE; 1104 1103 1105 struct advisory_lock *lock = NULL; 1106 while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) { 1104 LockList::Iterator iterator = locking->locks.GetIterator(); 1105 while (iterator.HasNext()) { 1106 struct advisory_lock *lock = iterator.Next(); 1107 1107 1108 if (lock->team == team) { 1108 flock->l_start = lock-> offset;1109 flock->l_len = lock-> length;1109 flock->l_start = lock->start; 1110 flock->l_len = lock->end - lock->start + 1; 1110 1111 status = B_OK; 1111 1112 break; … … 1115 1116 put_advisory_locking(locking); 1116 1117 return status; 1118 } 1119 1120 1121 /*! Returns \c true when either \a flock is \c NULL or the \a flock intersects 1122 with the advisory_lock \a lock. 1123 */ 1124 static bool 1125 advisory_lock_intersects(struct advisory_lock *lock, struct flock *flock) 1126 { 1127 if (flock == NULL) 1128 return true; 1129 1130 return lock->start <= flock->l_start - 1 + flock->l_len 1131 && lock->end >= flock->l_start; 1117 1132 } 1118 1133 … … 1128 1143 struct advisory_locking *locking = get_advisory_locking(vnode); 1129 1144 if (locking == NULL) 1130 return flock != NULL ? B_BAD_VALUE : B_OK; 1131 1145 return B_OK; 1146 1147 // TODO: use the thread ID instead?? 1132 1148 team_id team = team_get_current_team_id(); 1133 1149 pid_t session = thread_get_current_thread()->team->session_id; 1134 1150 1135 // find matching lock entry 1136 1137 status_t status = B_BAD_VALUE; 1138 struct advisory_lock *lock = NULL; 1139 while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, 1140 lock)) != NULL) { 1141 if (lock->team == team && (flock == NULL 1142 || (flock != NULL && lock->offset == flock->l_start 1143 && lock->length == flock->l_len)) 1144 || lock->session == session) { 1145 // we found our lock, free it 1146 list_remove_item(&locking->locks, lock); 1151 // find matching lock entries 1152 1153 LockList::Iterator iterator = locking->locks.GetIterator(); 1154 while (iterator.HasNext()) { 1155 struct advisory_lock *lock = iterator.Next(); 1156 bool removeLock = false; 1157 1158 if (lock->session == session) 1159 removeLock = true; 1160 else if (lock->team == team && advisory_lock_intersects(lock, flock)) { 1161 bool endsBeyond = false; 1162 bool startsBefore = false; 1163 if (flock != NULL) { 1164 startsBefore = lock->start < flock->l_start; 1165 endsBeyond = lock->end > flock->l_start - 1 + flock->l_len; 1166 } 1167 1168 if (!startsBefore && !endsBeyond) { 1169 // lock is completely contained in flock 1170 removeLock = true; 1171 } else if (startsBefore && !endsBeyond) { 1172 // cut the end of the lock 1173 lock->end = flock->l_start - 1; 1174 } else if (!startsBefore && endsBeyond) { 1175 // cut the start of the lock 1176 lock->start = flock->l_start + flock->l_len; 1177 } else { 1178 // divide the lock into two locks 1179 struct advisory_lock *secondLock = new advisory_lock; 1180 if (secondLock == NULL) { 1181 // TODO: we should probably revert the locks we already 1182 // changed... (ie. allocate upfront) 1183 put_advisory_locking(locking); 1184 return B_NO_MEMORY; 1185 } 1186 1187 lock->end = flock->l_start - 1; 1188 1189 secondLock->team = lock->team; 1190 secondLock->session = lock->session; 1191 // values must already be normalized when getting here 1192 secondLock->start = flock->l_start + flock->l_len; 1193 secondLock->end = lock->end; 1194 secondLock->shared = lock->shared; 1195 1196 locking->locks.Add(secondLock); 1197 } 1198 } 1199 1200 if (removeLock) { 1201 // this lock is no longer used 1202 iterator.Remove(); 1147 1203 free(lock); 1148 status = B_OK; 1149 break; 1150 } 1151 } 1152 1153 bool removeLocking = list_is_empty(&locking->locks); 1204 } 1205 } 1206 1207 bool removeLocking = locking->locks.IsEmpty(); 1154 1208 release_sem_etc(locking->wait_sem, 1, B_RELEASE_ALL); 1155 1209 1156 1210 put_advisory_locking(locking); 1157 1211 1158 if (status < B_OK)1159 return status;1160 1161 1212 if (removeLocking) { 1162 // we can remove the whole advisory locking structure; it's no longer used 1213 // We can remove the whole advisory locking structure; it's no 1214 // longer used 1163 1215 locking = get_advisory_locking(vnode); 1164 1216 if (locking != NULL) { 1165 1217 // the locking could have been changed in the mean time 1166 if (l ist_is_empty(&locking->locks)) {1218 if (locking->locks.IsEmpty()) { 1167 1219 vnode->advisory_locking = NULL; 1168 1220 1169 // we've detached the locking from the vnode, so we can safely delete it 1221 // we've detached the locking from the vnode, so we can 1222 // safely delete it 1170 1223 delete_sem(locking->lock); 1171 1224 delete_sem(locking->wait_sem); 1172 free(locking);1225 delete locking; 1173 1226 } else { 1174 1227 // the locking is in use again … … 1207 1260 // lock that one and search for any colliding file lock 1208 1261 struct advisory_locking *locking = get_advisory_locking(vnode); 1262 team_id team = team_get_current_team_id(); 1209 1263 sem_id waitForLock = -1; 1210 1264 1211 1265 if (locking != NULL) { 1212 1266 // test for collisions 1213 struct advisory_lock *lock = NULL; 1214 while ((lock = (struct advisory_lock *)list_get_next_item( 1215 &locking->locks, lock)) != NULL) { 1216 if (lock->offset <= flock->l_start + flock->l_len 1217 && lock->offset + lock->length > flock->l_start) { 1267 LockList::Iterator iterator = locking->locks.GetIterator(); 1268 while (iterator.HasNext()) { 1269 struct advisory_lock *lock = iterator.Next(); 1270 1271 // TODO: locks from the same team might be joinable! 1272 if (lock->team != team && advisory_lock_intersects(lock, flock)) { 1218 1273 // locks do overlap 1219 1274 if (!shared || !lock->shared) { … … 1272 1327 lock->session = session; 1273 1328 // values must already be normalized when getting here 1274 lock-> offset = flock->l_start;1275 lock-> length =flock->l_len;1329 lock->start = flock->l_start; 1330 lock->end = flock->l_start - 1 + flock->l_len; 1276 1331 lock->shared = shared; 1277 1332 1278 l ist_add_item(&locking->locks,lock);1333 locking->locks.Add(lock); 1279 1334 put_advisory_locking(locking); 1280 1335 … … 2368 2423 kprintf(" wait_sem: %ld", locking->wait_sem); 2369 2424 2370 struct advisory_lock *lock = NULL;2371 2425 int32 index = 0; 2372 while ((lock = (advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) { 2373 kprintf(" [%2ld] team: %ld\n", index, lock->team); 2374 kprintf(" offset: %Ld\n", lock->offset); 2375 kprintf(" length: %Ld\n", lock->length); 2426 LockList::Iterator iterator = locking->locks.GetIterator(); 2427 while (iterator.HasNext()) { 2428 struct advisory_lock *lock = iterator.Next(); 2429 2430 kprintf(" [%2ld] team: %ld\n", index++, lock->team); 2431 kprintf(" start: %Ld\n", lock->start); 2432 kprintf(" end: %Ld\n", lock->end); 2376 2433 kprintf(" shared? %s\n", lock->shared ? "yes" : "no"); 2377 2434 }
