Changeset 98d1b90
- Timestamp:
- Mar 21, 2022, 12:17:27 PM (2 years ago)
- Branches:
- ADT, ast-experimental, enum, master, pthread-emulation, qualifiedEnum
- Children:
- 4ecc35a
- Parents:
- adb3ea1 (diff), 41d3c8d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.hfa
radb3ea1 r98d1b90 164 164 } 165 165 166 static inline boollock(linear_backoff_then_block_lock & this) with(this) {166 static inline void lock(linear_backoff_then_block_lock & this) with(this) { 167 167 // if owner just return 168 if (active_thread() == owner) return true;168 if (active_thread() == owner) return; 169 169 size_t compare_val = 0; 170 170 int spin = spin_start; … … 172 172 for( ;; ) { 173 173 compare_val = 0; 174 if (internal_try_lock(this, compare_val)) return true;174 if (internal_try_lock(this, compare_val)) return; 175 175 if (2 == compare_val) break; 176 176 for (int i = 0; i < spin; i++) Pause(); … … 179 179 } 180 180 181 if(2 != compare_val && try_lock_contention(this)) return true;181 if(2 != compare_val && try_lock_contention(this)) return; 182 182 // block until signalled 183 while (block(this)) if(try_lock_contention(this)) return true; 184 185 // this should never be reached as block(this) always returns true 186 return false; 183 while (block(this)) if(try_lock_contention(this)) return; 187 184 } 188 185 -
libcfa/src/concurrency/mutex_stmt.hfa
radb3ea1 r98d1b90 12 12 }; 13 13 14 15 struct __mutex_stmt_lock_guard { 16 void ** lockarr; 17 __lock_size_t count; 18 }; 19 20 static inline void ?{}( __mutex_stmt_lock_guard & this, void * lockarr [], __lock_size_t count ) { 21 this.lockarr = lockarr; 22 this.count = count; 23 24 // Sort locks based on address 25 __libcfa_small_sort(this.lockarr, count); 26 27 // acquire locks in order 28 // for ( size_t i = 0; i < count; i++ ) { 29 // lock(*this.lockarr[i]); 30 // } 31 } 32 33 static inline void ^?{}( __mutex_stmt_lock_guard & this ) with(this) { 34 // for ( size_t i = count; i > 0; i-- ) { 35 // unlock(*lockarr[i - 1]); 36 // } 37 } 38 14 39 forall(L & | is_lock(L)) { 15 16 struct __mutex_stmt_lock_guard {17 L ** lockarr;18 __lock_size_t count;19 };20 21 static inline void ?{}( __mutex_stmt_lock_guard(L) & this, L * lockarr [], __lock_size_t count ) {22 this.lockarr = lockarr;23 this.count = count;24 25 // Sort locks based on address26 __libcfa_small_sort(this.lockarr, count);27 28 // acquire locks in order29 for ( size_t i = 0; i < count; i++ ) {30 lock(*this.lockarr[i]);31 }32 }33 34 static inline void ^?{}( __mutex_stmt_lock_guard(L) & this ) with(this) {35 for ( size_t i = count; i > 0; i-- ) {36 unlock(*lockarr[i - 1]);37 }38 }39 40 40 41 struct scoped_lock { … … 51 52 } 52 53 53 static inline L * __get_ptr( L & this ) {54 static inline void * __get_mutexstmt_lock_ptr( L & this ) { 54 55 return &this; 55 56 } 56 57 57 static inline L __get_ type( L & this );58 static inline L __get_mutexstmt_lock_type( L & this ); 58 59 59 static inline L __get_ type( L * this );60 static inline L __get_mutexstmt_lock_type( L * this ); 60 61 } -
src/Concurrency/Keywords.cc
radb3ea1 r98d1b90 1204 1204 //new TypeofType( noQualifiers, args.front()->clone() ) 1205 1205 new TypeofType( noQualifiers, new UntypedExpr( 1206 new NameExpr( "__get_ type" ),1206 new NameExpr( "__get_mutexstmt_lock_type" ), 1207 1207 { args.front()->clone() } 1208 1208 ) … … 1216 1216 map_range < std::list<Initializer*> > ( args, [](Expression * var ){ 1217 1217 return new SingleInit( new UntypedExpr( 1218 new NameExpr( "__get_ ptr" ),1218 new NameExpr( "__get_mutexstmt_lock_ptr" ), 1219 1219 { var } 1220 1220 ) ); … … 1227 1227 TypeExpr * lock_type_expr = new TypeExpr( 1228 1228 new TypeofType( noQualifiers, new UntypedExpr( 1229 new NameExpr( "__get_ type" ),1229 new NameExpr( "__get_mutexstmt_lock_type" ), 1230 1230 { args.front()->clone() } 1231 1231 ) -
src/Concurrency/KeywordsNew.cpp
radb3ea1 r98d1b90 14 14 // 15 15 16 #include <iostream> 17 16 18 #include "Concurrency/Keywords.h" 17 19 … … 26 28 #include "Common/Examine.h" 27 29 #include "Common/utility.h" 30 #include "Common/UniqueName.h" 28 31 #include "ControlStruct/LabelGeneratorNew.hpp" 29 32 #include "InitTweak/InitTweak.h" … … 167 170 const ast::StructDecl * typeid_decl = nullptr; 168 171 const ast::StructDecl * vtable_decl = nullptr; 172 169 173 }; 170 174 … … 874 878 875 879 // -------------------------------------------------------------------------- 876 struct MutexKeyword final {880 struct MutexKeyword final : public ast::WithDeclsToAdd<> { 877 881 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ); 878 882 void postvisit( const ast::StructDecl * decl ); … … 887 891 ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args ); 888 892 ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args ); 889 893 ast::ExprStmt * genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param); 894 ast::IfStmt * genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ); 890 895 private: 891 896 const ast::StructDecl * monitor_decl = nullptr; … … 896 901 897 902 static ast::ptr<ast::Type> generic_func; 903 904 UniqueName mutex_func_namer = UniqueName("__lock_unlock_curr"); 898 905 }; 899 906 … … 997 1004 998 1005 const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) { 1006 if ( !lock_guard_decl ) { 1007 SemanticError( stmt->location, "mutex stmt requires a header, add #include <mutex_stmt.hfa>\n" ); 1008 } 999 1009 ast::CompoundStmt * body = 1000 1010 new ast::CompoundStmt( stmt->location, { stmt->stmt } ); 1001 addStatements( body, stmt->mutexObjs );1002 return body;1011 1012 return addStatements( body, stmt->mutexObjs );; 1003 1013 } 1004 1014 … … 1195 1205 } 1196 1206 1207 // generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it 1208 // used to undo the type erasure done by storing all the lock pointers as void 1209 ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) { 1210 return new ast::ExprStmt( location, 1211 new ast::UntypedExpr( location, 1212 new ast::NameExpr( location, fnName ), { 1213 ast::UntypedExpr::createDeref( 1214 location, 1215 new ast::CastExpr( location, 1216 param, 1217 new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr( 1218 expr->location, 1219 new ast::NameExpr( expr->location, "__get_mutexstmt_lock_type" ), 1220 { expr } 1221 ) ) ), 1222 ast::GeneratedFlag::ExplicitCast 1223 ) 1224 ) 1225 } 1226 ) 1227 ); 1228 } 1229 1230 ast::IfStmt * MutexKeyword::genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ) { 1231 ast::IfStmt * outerLockIf = nullptr; 1232 ast::IfStmt * lastLockIf = nullptr; 1233 1234 //adds an if/elif clause for each lock to assign type from void ptr based on ptr address 1235 for ( long unsigned int i = 0; i < args.size(); i++ ) { 1236 1237 ast::UntypedExpr * ifCond = new ast::UntypedExpr( location, 1238 new ast::NameExpr( location, "?==?" ), { 1239 ast::deepCopy( thisParam ), 1240 new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() )) 1241 } 1242 ); 1243 1244 ast::IfStmt * currLockIf = new ast::IfStmt( 1245 location, 1246 ifCond, 1247 genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) ) 1248 ); 1249 1250 if ( i == 0 ) { 1251 outerLockIf = currLockIf; 1252 } else { 1253 // add ifstmt to else of previous stmt 1254 lastLockIf->else_ = currLockIf; 1255 } 1256 1257 lastLockIf = currLockIf; 1258 } 1259 return outerLockIf; 1260 } 1261 1197 1262 ast::CompoundStmt * MutexKeyword::addStatements( 1198 1263 const ast::CompoundStmt * body, 1199 1264 const std::vector<ast::ptr<ast::Expr>> & args ) { 1200 ast::CompoundStmt * mutBody = ast::mutate( body );1201 1265 1202 1266 // Code is generated near the beginning of the compound statement. 1203 const CodeLocation & location = mutBody->location; 1267 const CodeLocation & location = body->location; 1268 1269 // final body to return 1270 ast::CompoundStmt * newBody = new ast::CompoundStmt( location ); 1271 1272 // std::string lockFnName = mutex_func_namer.newName(); 1273 // std::string unlockFnName = mutex_func_namer.newName(); 1204 1274 1205 1275 // Make pointer to the monitors. … … 1209 1279 new ast::ArrayType( 1210 1280 new ast::PointerType( 1211 new ast::TypeofType( 1212 new ast::UntypedExpr( 1213 location, 1214 new ast::NameExpr( location, "__get_type" ), 1215 { args.front() } 1216 ) 1217 ) 1281 new ast::VoidType() 1218 1282 ), 1219 1283 ast::ConstantExpr::from_ulong( location, args.size() ), … … 1229 1293 new ast::UntypedExpr( 1230 1294 expr->location, 1231 new ast::NameExpr( expr->location, "__get_ ptr" ),1295 new ast::NameExpr( expr->location, "__get_mutexstmt_lock_ptr" ), 1232 1296 { expr } 1233 1297 ) … … 1242 1306 ast::StructInstType * lock_guard_struct = 1243 1307 new ast::StructInstType( lock_guard_decl ); 1244 ast::TypeExpr * lock_type_expr = new ast::TypeExpr( 1245 location, 1246 new ast::TypeofType( 1247 new ast::UntypedExpr( 1248 location, 1249 new ast::NameExpr( location, "__get_type" ), 1250 { args.front() } 1251 ) 1252 ) 1253 ); 1254 1255 lock_guard_struct->params.push_back( lock_type_expr ); 1256 1257 // In reverse order: 1308 1309 // use try stmts to lock and finally to unlock 1310 ast::TryStmt * outerTry = nullptr; 1311 ast::TryStmt * currentTry; 1312 ast::CompoundStmt * lastBody = nullptr; 1313 1314 // adds a nested try stmt for each lock we are locking 1315 for ( long unsigned int i = 0; i < args.size(); i++ ) { 1316 ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 1317 location, 1318 new ast::NameExpr( location,"?[?]" ), { 1319 new ast::NameExpr( location, "__monitors" ), 1320 ast::ConstantExpr::from_int( location, i ) 1321 } 1322 ); 1323 1324 // make the try body 1325 ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location ); 1326 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess ); 1327 currTryBody->push_back( lockCall ); 1328 1329 // make the finally stmt 1330 ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location ); 1331 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess ); 1332 currFinallyBody->push_back( unlockCall ); 1333 1334 // construct the current try 1335 currentTry = new ast::TryStmt( 1336 location, 1337 currTryBody, 1338 {}, 1339 new ast::FinallyStmt( location, currFinallyBody ) 1340 ); 1341 if ( i == 0 ) outerTry = currentTry; 1342 else { 1343 // pushback try into the body of the outer try 1344 lastBody->push_back( currentTry ); 1345 } 1346 lastBody = currTryBody; 1347 } 1348 1349 // push body into innermost try body 1350 if ( lastBody != nullptr ) { 1351 lastBody->push_back( body ); 1352 newBody->push_front( outerTry ); 1353 } 1354 1258 1355 // monitor_guard_t __guard = { __monitors, # }; 1259 mutBody->push_front(1356 newBody->push_front( 1260 1357 new ast::DeclStmt( 1261 1358 location, … … 1284 1381 1285 1382 // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) }; 1286 mutBody->push_front( new ast::DeclStmt( location, monitors ) ); 1287 1288 return mutBody; 1383 newBody->push_front( new ast::DeclStmt( location, monitors ) ); 1384 1385 // // The parameter for both __lock_curr/__unlock_curr routines. 1386 // ast::ObjectDecl * this_decl = new ast::ObjectDecl( 1387 // location, 1388 // "this", 1389 // new ast::PointerType( new ast::VoidType() ), 1390 // nullptr, 1391 // {}, 1392 // ast::Linkage::Cforall 1393 // ); 1394 1395 // ast::FunctionDecl * lock_decl = new ast::FunctionDecl( 1396 // location, 1397 // lockFnName, 1398 // { /* forall */ }, 1399 // { 1400 // // Copy the declaration of this. 1401 // this_decl, 1402 // }, 1403 // { /* returns */ }, 1404 // nullptr, 1405 // 0, 1406 // ast::Linkage::Cforall, 1407 // { /* attributes */ }, 1408 // ast::Function::Inline 1409 // ); 1410 1411 // ast::FunctionDecl * unlock_decl = new ast::FunctionDecl( 1412 // location, 1413 // unlockFnName, 1414 // { /* forall */ }, 1415 // { 1416 // // Copy the declaration of this. 1417 // ast::deepCopy( this_decl ), 1418 // }, 1419 // { /* returns */ }, 1420 // nullptr, 1421 // 0, 1422 // ast::Linkage::Cforall, 1423 // { /* attributes */ }, 1424 // ast::Function::Inline 1425 // ); 1426 1427 // ast::IfStmt * outerLockIf = nullptr; 1428 // ast::IfStmt * outerUnlockIf = nullptr; 1429 // ast::IfStmt * lastLockIf = nullptr; 1430 // ast::IfStmt * lastUnlockIf = nullptr; 1431 1432 // //adds an if/elif clause for each lock to assign type from void ptr based on ptr address 1433 // for ( long unsigned int i = 0; i < args.size(); i++ ) { 1434 // ast::VariableExpr * thisParam = new ast::VariableExpr( location, InitTweak::getParamThis( lock_decl ) ); 1435 // ast::UntypedExpr * ifCond = new ast::UntypedExpr( location, 1436 // new ast::NameExpr( location, "?==?" ), { 1437 // thisParam, 1438 // new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() )) 1439 // } 1440 // ); 1441 1442 // ast::IfStmt * currLockIf = new ast::IfStmt( 1443 // location, 1444 // ast::deepCopy( ifCond ), 1445 // genVirtLockUnlockExpr( "lock", args.at(i), location, ast::deepCopy( thisParam ) ) 1446 // ); 1447 1448 // ast::IfStmt * currUnlockIf = new ast::IfStmt( 1449 // location, 1450 // ifCond, 1451 // genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) ) 1452 // ); 1453 1454 // if ( i == 0 ) { 1455 // outerLockIf = currLockIf; 1456 // outerUnlockIf = currUnlockIf; 1457 // } else { 1458 // // add ifstmt to else of previous stmt 1459 // lastLockIf->else_ = currLockIf; 1460 // lastUnlockIf->else_ = currUnlockIf; 1461 // } 1462 1463 // lastLockIf = currLockIf; 1464 // lastUnlockIf = currUnlockIf; 1465 // } 1466 1467 // // add pointer typing if/elifs to body of routines 1468 // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } ); 1469 // unlock_decl->stmts = new ast::CompoundStmt( location, { outerUnlockIf } ); 1470 1471 // // add routines to scope 1472 // declsToAddBefore.push_back( lock_decl ); 1473 // declsToAddBefore.push_back( unlock_decl ); 1474 1475 // newBody->push_front(new ast::DeclStmt( location, lock_decl )); 1476 // newBody->push_front(new ast::DeclStmt( location, unlock_decl )); 1477 1478 return newBody; 1289 1479 } 1290 1480 -
tests/concurrent/mutexstmt/.expect/locks.txt
radb3ea1 r98d1b90 3 3 Start Test: multi lock deadlock/mutual exclusion 4 4 End Test: multi lock deadlock/mutual exclusion 5 Start Test: multi polymorphic lock deadlock/mutual exclusion 6 End Test: multi polymorphic lock deadlock/mutual exclusion -
tests/concurrent/mutexstmt/locks.cfa
radb3ea1 r98d1b90 4 4 5 5 const unsigned int num_times = 10000; 6 7 Duration default_preemption() { return 0; } 6 8 7 9 single_acquisition_lock m1, m2, m3, m4, m5; … … 23 25 } 24 26 27 void refTest( single_acquisition_lock & m ) { 28 mutex ( m ) { 29 assert(!insideFlag); 30 insideFlag = true; 31 assert(insideFlag); 32 insideFlag = false; 33 } 34 } 35 25 36 thread T_Multi {}; 26 37 27 38 void main( T_Multi & this ) { 28 39 for (unsigned int i = 0; i < num_times; i++) { 40 refTest( m1 ); 29 41 mutex ( m1 ) { 30 42 assert(!insideFlag); … … 60 72 } 61 73 74 single_acquisition_lock l1; 75 linear_backoff_then_block_lock l2; 76 owner_lock l3; 77 78 thread T_Multi_Poly {}; 79 80 void main( T_Multi_Poly & this ) { 81 for (unsigned int i = 0; i < num_times; i++) { 82 refTest( l1 ); 83 mutex ( l1 ) { 84 assert(!insideFlag); 85 insideFlag = true; 86 assert(insideFlag); 87 insideFlag = false; 88 } 89 mutex ( l1, l2, l3 ) { 90 assert(!insideFlag); 91 insideFlag = true; 92 assert(insideFlag); 93 insideFlag = false; 94 } 95 mutex ( l3, l1 ) { 96 assert(!insideFlag); 97 insideFlag = true; 98 assert(insideFlag); 99 insideFlag = false; 100 } 101 mutex ( l1, l2 ) { 102 assert(!insideFlag); 103 insideFlag = true; 104 assert(insideFlag); 105 insideFlag = false; 106 } 107 } 108 } 109 62 110 int num_tasks = 10; 63 111 int main() { 64 processor p[ 10];112 processor p[num_tasks - 1]; 65 113 66 114 printf("Start Test: single lock mutual exclusion\n"); 67 115 { 68 T_Mutex t[ 10];116 T_Mutex t[num_tasks]; 69 117 } 70 118 assert(count == num_tasks * num_times); … … 72 120 printf("Start Test: multi lock deadlock/mutual exclusion\n"); 73 121 { 74 T_Multi t[ 10];122 T_Multi t[num_tasks]; 75 123 } 76 124 printf("End Test: multi lock deadlock/mutual exclusion\n"); 125 printf("Start Test: multi polymorphic lock deadlock/mutual exclusion\n"); 126 { 127 T_Multi_Poly t[num_tasks]; 128 } 129 printf("End Test: multi polymorphic lock deadlock/mutual exclusion\n"); 77 130 }
Note: See TracChangeset
for help on using the changeset viewer.