1319 asm("ldmfd sp!, {r0,lr} "); |
1319 asm("ldmfd sp!, {r0,lr} "); |
1320 asm("b 1b "); |
1320 asm("b 1b "); |
1321 #endif |
1321 #endif |
1322 } |
1322 } |
1323 |
1323 |
|
1324 EXPORT_C __NAKED__ TInt RFastLock::Poll() |
|
1325 { |
|
1326 asm("1: "); |
|
1327 asm("add r0, r0, #4 "); // point to iCount |
|
1328 |
|
1329 #ifdef __CPU_ARM_HAS_LDREX_STREX |
|
1330 asm("2: "); |
|
1331 LDREX( 2, 0); // read |
|
1332 asm("subs r1, r2, #1 "); // decrement |
|
1333 asm("bcs 3f "); // if no borrow, lock cannot be obtained so bail out |
|
1334 STREX( 3, 1, 0); // write |
|
1335 asm("teq r3, #0 "); // success? |
|
1336 asm("bne 2b "); // no! |
|
1337 asm("mov r0, #0 "); // lock acquired so return KErrNone |
|
1338 #ifdef __SMP__ |
|
1339 __DATA_MEMORY_BARRIER__(r3); // need acquire barrier |
|
1340 #endif |
|
1341 __JUMP(, lr); |
|
1342 |
|
1343 asm("3: "); |
|
1344 asm("mov r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else can't get it immediately so return KErrTimedOut |
|
1345 __JUMP(, lr); |
|
1346 #else // no LDREX/STREX - ARM arch 5 CPU |
|
1347 asm("mov r1, #1 "); // 'looking' value |
|
1348 asm("swp r1, r1, [r0] "); // write looking value, read original |
|
1349 asm("subs r2, r1, #1 "); // decrement count |
|
1350 asm("strcc r2, [r0] "); // if borrow, was originally zero so write back -1 and return KErrNone |
|
1351 asm("movcc r0, #0 "); // got lock - return KErrNone |
|
1352 __JUMP(cc, lr); |
|
1353 |
|
1354 asm("strlt r1, [r0] "); // else if result<0 (i.e. wasn't looking value) write back original |
|
1355 asm("mov r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else can't get it immediately so return KErrTimedOut |
|
1356 __JUMP(, lr); |
|
1357 #endif |
|
1358 } |
|
1359 |
1324 EXPORT_C __NAKED__ void RFastLock::Signal() |
1360 EXPORT_C __NAKED__ void RFastLock::Signal() |
1325 { |
1361 { |
1326 asm("1: "); |
1362 asm("1: "); |
1327 asm("add r0, r0, #4 "); // point to iCount |
1363 asm("add r0, r0, #4 "); // point to iCount |
1328 |
1364 |
1351 asm("mov r0, #1000 "); // someone was looking, so wait 1ms and try again |
1387 asm("mov r0, #1000 "); // someone was looking, so wait 1ms and try again |
1352 asm("bl " CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32); |
1388 asm("bl " CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32); |
1353 asm("ldmfd sp!, {r0,lr} "); |
1389 asm("ldmfd sp!, {r0,lr} "); |
1354 asm("b 1b "); |
1390 asm("b 1b "); |
1355 #endif |
1391 #endif |
|
1392 } |
|
1393 |
|
1394 |
|
1395 /** |
|
1396 Acquire the lock, if necessary waiting up to a specified maximum amount of time |
|
1397 for it to become free. |
|
1398 |
|
1399 This function checks if the lock is currently held. If not the lock is marked |
|
1400 as held by the current thread and the call returns immediately. If the lock is |
|
1401 held by another thread the current thread will suspend until the lock becomes |
|
1402 free or until the specified timeout period has elapsed. |
|
1403 |
|
1404 @param aTimeout The timeout value in microseconds |
|
1405 |
|
1406 @return KErrNone if the lock was acquired successfully. |
|
1407 KErrTimedOut if the timeout has expired. |
|
1408 KErrGeneral if the lock is being reset, i.e the lock |
|
1409 is about to be deleted. |
|
1410 KErrArgument if aTimeout is negative; |
|
1411 otherwise one of the other system wide error codes. |
|
1412 */ |
|
1413 EXPORT_C __NAKED__ TInt RFastLock::Wait(TInt /*aTimeout*/) |
|
1414 { |
|
1415 asm("stmfd sp!, {r4-r6,lr} "); |
|
1416 asm("add r4, r0, #4 "); // r4->iCount |
|
1417 asm("subs r5, r1, #0 "); // r5=aTimeout |
|
1418 asm("mov r6, #1000 "); |
|
1419 asm("movle r0, #%a0" : : "i" ((TInt)KErrArgument)); |
|
1420 __CPOPRET(le, "r4-r6,"); // if aTimeout<=0 return KErrArgument |
|
1421 asm("1: "); |
|
1422 |
|
1423 #ifdef __CPU_ARM_HAS_LDREX_STREX |
|
1424 asm("2: "); |
|
1425 LDREX( 2, 4); // read |
|
1426 asm("subs r12, r2, #1 "); // decrement |
|
1427 STREX( 3, 12, 4); // write |
|
1428 asm("teq r3, #0 "); // success? |
|
1429 asm("bne 2b "); // no! |
|
1430 asm("bcs 8f "); // if no borrow from decrement, need to wait |
|
1431 #ifdef __SMP__ |
|
1432 __DATA_MEMORY_BARRIER__(r3); // no need to wait, but still need acquire barrier |
|
1433 #endif |
|
1434 #else // no LDREX/STREX - ARM arch 5 CPU |
|
1435 asm("mov r2, #1 "); // 'looking' value |
|
1436 asm("swp r2, r2, [r4] "); // write looking value, read original |
|
1437 asm("subs r12, r2, #1 "); // decrement count |
|
1438 asm("strlt r12, [r4] "); // if it becomes negative, no-one was looking |
|
1439 asm("bcs 8f "); // if no borrow, we have to wait |
|
1440 #endif |
|
1441 asm("mov r0, #0 "); // return KErrNone |
|
1442 __POPRET("r4-r6,"); |
|
1443 |
|
1444 // We need to wait |
|
1445 asm("8: "); |
|
1446 #ifndef __CPU_ARM_HAS_LDREX_STREX |
|
1447 // no LDREX/STREX - ARM arch 5 CPU |
|
1448 asm("blt 3f "); // if it wasn't 'looking' value, branch |
|
1449 |
|
1450 // it was the 'looking' value, so wait a little bit |
|
1451 asm("cmp r5, #0 "); |
|
1452 asm("ble 9f "); // waited too long already, return KErrTimedOut |
|
1453 asm("sub r5, r5, r6 "); |
|
1454 asm("mov r6, #2000 "); |
|
1455 asm("mov r0, #1000 "); // wait 1ms |
|
1456 asm("cmp r5, r0 "); |
|
1457 asm("movlt r5, r0 "); // remaining time at least 1ms |
|
1458 asm("bl " CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32); |
|
1459 asm("b 1b "); // try again |
|
1460 #endif |
|
1461 asm("3: "); |
|
1462 asm("sub r0, r4, #4 "); // r0=this |
|
1463 asm("mov r1, r5 "); // r1=aTimeout |
|
1464 asm("bl " CSM_ZN10RSemaphore4WaitEi); // try to acquire semaphore |
|
1465 asm("cmp r0, #%a0" : : "i" ((TInt)KErrTimedOut)); |
|
1466 __CPOPRET(ne, "r4-r6,"); // if wait didn't time out, return |
|
1467 asm("mov r5, #1 "); // any further timed waits will be for minimum period |
|
1468 |
|
1469 // Before we can return KErrTimedOut we must increment iCount (since we |
|
1470 // previously decremented it in anticipation of acquiring the lock. |
|
1471 // However we must not increment iCount if it would become zero, since |
|
1472 // the semaphore will have been signalled (to counterbalance the Wait() |
|
1473 // which timed out and thus never happened). This would result in two |
|
1474 // threads being able to acquire the lock simultaneously - one by |
|
1475 // decrementing iCount from 0 to -1 without looking at the semaphore, |
|
1476 // and the other by decrementing iCount from -1 to -2 and then absorbing |
|
1477 // the spurious semaphore signal. |
|
1478 // orig = __e32_atomic_tas_ord32(&iCount, -1, 0, 1); // don't release lock completely |
|
1479 // if (orig < -1) |
|
1480 // return KErrTimedOut; // count corrected - don't need to touch semaphore |
|
1481 // lock is actually free at this point, try again to claim it |
|
1482 // aTimeout = 1; |
|
1483 #ifdef __CPU_ARM_HAS_LDREX_STREX |
|
1484 #ifdef __SMP__ |
|
1485 __DATA_MEMORY_BARRIER_Z__(r3); |
|
1486 #endif |
|
1487 asm("4: "); |
|
1488 LDREX( 2, 4); // read |
|
1489 asm("adds r2, r2, #1 "); // increment |
|
1490 asm("bge 3b "); // if increment would make result >=0, wait again |
|
1491 STREX( 3, 2, 4); // write |
|
1492 asm("teq r3, #0 "); // success? |
|
1493 asm("bne 4b "); // no! |
|
1494 #ifdef __SMP__ |
|
1495 __DATA_MEMORY_BARRIER__(r3); |
|
1496 #endif |
|
1497 #else // no LDREX/STREX - ARM arch 5 CPU |
|
1498 asm("mov r2, #1 "); // 'looking' value |
|
1499 asm("swp r2, r2, [r4] "); // write looking value, read original |
|
1500 asm("adds r12, r2, #1 "); // increment count |
|
1501 asm("strlt r12, [r4] "); // if still negative, count now fixed, so return KErrTimedOut |
|
1502 asm("streq r2, [r4] "); // else if not 'looking' value, write back original |
|
1503 asm("bge 3b "); // if 'looking' value or -1, wait again |
|
1504 #endif |
|
1505 asm("9: "); |
|
1506 asm("mov r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // return KErrTimedOut |
|
1507 __POPRET("r4-r6,"); |
1356 } |
1508 } |
1357 |
1509 |
1358 |
1510 |
1359 // Entry point stub to allow EKA1 binaries to be executed under EKA2 |
1511 // Entry point stub to allow EKA1 binaries to be executed under EKA2 |
1360 // Only called when process is first loaded |
1512 // Only called when process is first loaded |