@@ -998,44 +998,65 @@ static_assert(sizeof(ActiveActorStatus) == ACTIVE_ACTOR_STATUS_SIZE,
998
998
// / exist yet. As a result, the subset of rules that currently apply
999
999
// / are (1), (3), (5), (6).
1000
1000
class DefaultActorImpl : public HeapObject {
1001
+ struct Header {
1001
1002
#if SWIFT_CONCURRENCY_ACTORS_AS_LOCKS
1002
- // If actors are locks, we don't need to maintain any extra bookkeeping in the
1003
- // ActiveActorStatus since all threads which are contending will block
1004
- // synchronously, no job queue is needed and the lock will handle all priority
1005
- // escalation logic
1006
- Mutex drainLock;
1003
+ // If actors are locks, we don't need to maintain any extra bookkeeping in the
1004
+ // ActiveActorStatus since all threads which are contending will block
1005
+ // synchronously, no job queue is needed and the lock will handle all priority
1006
+ // escalation logic
1007
+ Mutex drainLock;
1007
1008
#else
1008
- // Note: There is some padding that is added here by the compiler in order to
1009
- // enforce alignment. This is space that is available for us to use in
1010
- // the future
1011
- alignas (sizeof (ActiveActorStatus)) char StatusStorage[sizeof(ActiveActorStatus)];
1009
+ // Note: There is some padding that is added here by the compiler in order to
1010
+ // enforce alignment. This is space that is available for us to use in
1011
+ // the future
1012
+ alignas (sizeof (ActiveActorStatus)) char StatusStorage[sizeof(ActiveActorStatus)];
1013
+ #endif
1014
+ // TODO (rokhinip): Make this a flagset
1015
+ bool isDistributedRemoteActor;
1016
+ } header;
1012
1017
1018
+ #if !SWIFT_CONCURRENCY_ACTORS_AS_LOCKS
1013
1019
using SimpleQueue = swift::SimpleQueue<Job *, JobQueueTraits>;
1014
1020
using PriorityQueue = swift::PriorityQueue<Job *, JobQueueTraits>;
1015
1021
1016
- // When enqueued, jobs are atomically added to a linked list with the head
1017
- // stored inside ActiveActorStatus. This list contains jobs in the LIFO order
1018
- // regardless of their priorities.
1019
- //
1020
- // After that processing thread collects them and adds to the
1021
- // `prioritisedJobs` while holding the actor lock.
1022
- //
1023
- // TODO: Move this to the end of the actor memory to minimise false sharing
1024
- //
1025
- PriorityQueue prioritisedJobs;
1022
+ struct Footer {
1023
+ // When enqueued, jobs are atomically added to a linked list with the head
1024
+ // stored inside ActiveActorStatus. This list contains jobs in the LIFO order
1025
+ // regardless of their priorities.
1026
+ //
1027
+ // After that processing thread collects them and adds to the
1028
+ // `prioritisedJobs` while holding the actor lock.
1029
+ //
1030
+ PriorityQueue prioritisedJobs;
1031
+ };
1032
+
1033
+ struct Padding {
1034
+ enum {
1035
+ // Available space
1036
+ x1 = (int )(sizeof (void *) * NumWords_DefaultActor),
1037
+ // ... subtracting size of footer
1038
+ x2 = x1 - (int )sizeof (Footer),
1039
+ // ... ensuring footer is aligned
1040
+ x3 = x2 - (int )(x2 % alignof (Footer)),
1041
+ // ... subtracting size of header
1042
+ x4 = x3 - (int )sizeof (Header),
1043
+ // ... subtracting padding before header
1044
+ size = x4 - (int )((alignof (Header) - sizeof (HeapObject) % alignof (Header)) % alignof (Header))
1045
+ };
1046
+ };
1047
+ char padding[Padding::size];
1048
+ Footer footer;
1026
1049
#endif
1027
- // TODO (rokhinip): Make this a flagset
1028
- bool isDistributedRemoteActor;
1029
1050
1030
1051
public:
1031
1052
// / Properly construct an actor, except for the heap header.
1032
1053
void initialize (bool isDistributedRemote = false ) {
1033
- this ->isDistributedRemoteActor = isDistributedRemote;
1054
+ this ->header . isDistributedRemoteActor = isDistributedRemote;
1034
1055
#if SWIFT_CONCURRENCY_ACTORS_AS_LOCKS
1035
- new (&this ->drainLock ) Mutex ();
1056
+ new (&this ->header . drainLock ) Mutex ();
1036
1057
#else
1037
1058
_status ().store (ActiveActorStatus (), std::memory_order_relaxed);
1038
- new (&this ->prioritisedJobs ) PriorityQueue ();
1059
+ new (&this ->footer . prioritisedJobs ) PriorityQueue ();
1039
1060
#endif
1040
1061
SWIFT_TASK_DEBUG_LOG (" Creating default actor %p" , this );
1041
1062
concurrency::trace::actor_create (this );
@@ -1075,20 +1096,25 @@ class DefaultActorImpl : public HeapObject {
1075
1096
1076
1097
#if !SWIFT_CONCURRENCY_ACTORS_AS_LOCKS
1077
1098
swift::atomic<ActiveActorStatus> &_status () {
1078
- return reinterpret_cast <swift::atomic<ActiveActorStatus>&> (this ->StatusStorage );
1099
+ return reinterpret_cast <swift::atomic<ActiveActorStatus>&> (this ->header . StatusStorage );
1079
1100
}
1080
1101
1081
1102
const swift::atomic<ActiveActorStatus> &_status () const {
1082
- return reinterpret_cast <const swift::atomic<ActiveActorStatus>&> (this ->StatusStorage );
1103
+ return reinterpret_cast <const swift::atomic<ActiveActorStatus>&> (this ->header . StatusStorage );
1083
1104
}
1084
1105
1085
1106
// Only for static assert use below, not for actual use otherwise
1086
1107
static constexpr size_t offsetOfActiveActorStatus () {
1087
1108
#pragma clang diagnostic push
1088
1109
#pragma clang diagnostic ignored "-Winvalid-offsetof"
1089
- return offsetof (DefaultActorImpl, StatusStorage);
1110
+ return offsetof (DefaultActorImpl, header. StatusStorage );
1090
1111
#pragma clang diagnostic pop
1091
1112
}
1113
+
1114
+ PriorityQueue &_prioritisedJobs () {
1115
+ return footer.prioritisedJobs ;
1116
+ }
1117
+
1092
1118
#endif /* !SWIFT_CONCURRENCY_ACTORS_AS_LOCKS */
1093
1119
1094
1120
private:
@@ -1417,7 +1443,7 @@ void DefaultActorImpl::processJobs() {
1417
1443
auto job = jobs.head ;
1418
1444
while (job) {
1419
1445
auto next = getNextJob (job);
1420
- prioritisedJobs .enqueue (job);
1446
+ _prioritisedJobs () .enqueue (job);
1421
1447
job = next;
1422
1448
}
1423
1449
}
@@ -1427,8 +1453,8 @@ Job *DefaultActorImpl::drainOne() {
1427
1453
SWIFT_TASK_DEBUG_LOG (" Draining one job from default actor %p" , this );
1428
1454
1429
1455
processJobs ();
1430
- traceJobQueue (this , prioritisedJobs .peek ());
1431
- auto firstJob = prioritisedJobs .dequeue ();
1456
+ traceJobQueue (this , _prioritisedJobs () .peek ());
1457
+ auto firstJob = _prioritisedJobs () .dequeue ();
1432
1458
if (!firstJob) {
1433
1459
SWIFT_TASK_DEBUG_LOG (" No jobs to drain on actor %p" , this );
1434
1460
} else {
@@ -1673,7 +1699,7 @@ retry:;
1673
1699
std::memory_order_relaxed)) {
1674
1700
_swift_tsan_acquire (this );
1675
1701
if (assertNoJobs) {
1676
- assert (prioritisedJobs .empty ());
1702
+ assert (_prioritisedJobs () .empty ());
1677
1703
}
1678
1704
traceActorStateTransition (this , oldState, newState, distributedActorIsRemote);
1679
1705
return true ;
@@ -1724,7 +1750,7 @@ bool DefaultActorImpl::unlock(bool forceUnlock)
1724
1750
1725
1751
auto newState = oldState;
1726
1752
// Lock is still held at this point, so it is safe to access prioritisedJobs
1727
- if (!prioritisedJobs .empty () || oldState.getFirstUnprioritisedJob ()) {
1753
+ if (!_prioritisedJobs () .empty () || oldState.getFirstUnprioritisedJob ()) {
1728
1754
// There is work left to do, don't unlock the actor
1729
1755
if (!forceUnlock) {
1730
1756
SWIFT_TASK_DEBUG_LOG (" Unlock-ing actor %p failed" , this );
@@ -2245,5 +2271,5 @@ bool swift::swift_distributed_actor_is_remote(HeapObject *_actor) {
2245
2271
}
2246
2272
2247
2273
bool DefaultActorImpl::isDistributedRemote () {
2248
- return this ->isDistributedRemoteActor ;
2274
+ return this ->header . isDistributedRemoteActor ;
2249
2275
}
0 commit comments