@@ -2097,121 +2097,76 @@ static bool yield_to_task_scx(struct rq *rq, struct task_struct *to)
2097
2097
#ifdef CONFIG_SMP
2098
2098
/**
2099
2099
* move_task_to_local_dsq - Move a task from a different rq to a local DSQ
2100
- * @rq: rq to move the task into, currently locked
2101
2100
* @p: task to move
2102
2101
* @enq_flags: %SCX_ENQ_*
2102
+ * @src_rq: rq to move the task from, locked on entry, released on return
2103
+ * @dst_rq: rq to move the task into, locked on return
2103
2104
*
2104
- * Move @p which is currently on a different rq to @rq 's local DSQ. The caller
2105
+ * Move @p which is currently on @src_rq to @dst_rq 's local DSQ. The caller
2105
2106
* must:
2106
2107
*
2107
2108
* 1. Start with exclusive access to @p either through its DSQ lock or
2108
2109
* %SCX_OPSS_DISPATCHING flag.
2109
2110
*
2110
2111
* 2. Set @p->scx.holding_cpu to raw_smp_processor_id().
2111
2112
*
2112
- * 3. Remember task_rq(@p). Release the exclusive access so that we don't
2113
- * deadlock with dequeue.
2113
+ * 3. Remember task_rq(@p) as @src_rq . Release the exclusive access so that we
2114
+ * don't deadlock with dequeue.
2114
2115
*
2115
- * 4. Lock @rq and the task_rq from #3.
2116
+ * 4. Lock @src_rq from #3.
2116
2117
*
2117
2118
* 5. Call this function.
2118
2119
*
2119
2120
* Returns %true if @p was successfully moved. %false after racing dequeue and
2120
- * losing.
2121
+ * losing. On return, @src_rq is unlocked and @dst_rq is locked.
2121
2122
*/
2122
- static bool move_task_to_local_dsq (struct rq * rq , struct task_struct * p ,
2123
- u64 enq_flags )
2123
+ static bool move_task_to_local_dsq (struct task_struct * p , u64 enq_flags ,
2124
+ struct rq * src_rq , struct rq * dst_rq )
2124
2125
{
2125
- struct rq * task_rq ;
2126
-
2127
- lockdep_assert_rq_held (rq );
2126
+ lockdep_assert_rq_held (src_rq );
2128
2127
2129
2128
/*
2130
- * If dequeue got to @p while we were trying to lock both rq's , it'd
2131
- * have cleared @p->scx.holding_cpu to -1. While other cpus may have
2132
- * updated it to different values afterwards, as this operation can't be
2129
+ * If dequeue got to @p while we were trying to lock @src_rq , it'd have
2130
+ * cleared @p->scx.holding_cpu to -1. While other cpus may have updated
2131
+ * it to different values afterwards, as this operation can't be
2133
2132
* preempted or recurse, @p->scx.holding_cpu can never become
2134
2133
* raw_smp_processor_id() again before we're done. Thus, we can tell
2135
2134
* whether we lost to dequeue by testing whether @p->scx.holding_cpu is
2136
2135
* still raw_smp_processor_id().
2137
2136
*
2137
+ * @p->rq couldn't have changed if we're still the holding cpu.
2138
+ *
2138
2139
* See dispatch_dequeue() for the counterpart.
2139
2140
*/
2140
- if (unlikely (p -> scx .holding_cpu != raw_smp_processor_id ()))
2141
+ if (unlikely (p -> scx .holding_cpu != raw_smp_processor_id ()) ||
2142
+ WARN_ON_ONCE (src_rq != task_rq (p ))) {
2143
+ raw_spin_rq_unlock (src_rq );
2144
+ raw_spin_rq_lock (dst_rq );
2141
2145
return false;
2146
+ }
2142
2147
2143
- /* @p->rq couldn't have changed if we're still the holding cpu */
2144
- task_rq = task_rq (p );
2145
- lockdep_assert_rq_held (task_rq );
2148
+ /* the following marks @p MIGRATING which excludes dequeue */
2149
+ deactivate_task (src_rq , p , 0 );
2150
+ set_task_cpu (p , cpu_of (dst_rq ));
2151
+ p -> scx .sticky_cpu = cpu_of (dst_rq );
2146
2152
2147
- WARN_ON_ONCE (!cpumask_test_cpu (cpu_of (rq ), p -> cpus_ptr ));
2148
- deactivate_task (task_rq , p , 0 );
2149
- set_task_cpu (p , cpu_of (rq ));
2150
- p -> scx .sticky_cpu = cpu_of (rq );
2153
+ raw_spin_rq_unlock (src_rq );
2154
+ raw_spin_rq_lock (dst_rq );
2151
2155
2152
2156
/*
2153
2157
* We want to pass scx-specific enq_flags but activate_task() will
2154
2158
* truncate the upper 32 bit. As we own @rq, we can pass them through
2155
2159
* @rq->scx.extra_enq_flags instead.
2156
2160
*/
2157
- WARN_ON_ONCE (rq -> scx .extra_enq_flags );
2158
- rq -> scx .extra_enq_flags = enq_flags ;
2159
- activate_task (rq , p , 0 );
2160
- rq -> scx .extra_enq_flags = 0 ;
2161
+ WARN_ON_ONCE (!cpumask_test_cpu (cpu_of (dst_rq ), p -> cpus_ptr ));
2162
+ WARN_ON_ONCE (dst_rq -> scx .extra_enq_flags );
2163
+ dst_rq -> scx .extra_enq_flags = enq_flags ;
2164
+ activate_task (dst_rq , p , 0 );
2165
+ dst_rq -> scx .extra_enq_flags = 0 ;
2161
2166
2162
2167
return true;
2163
2168
}
2164
2169
2165
- /**
2166
- * dispatch_to_local_dsq_lock - Ensure source and destination rq's are locked
2167
- * @rq: current rq which is locked
2168
- * @src_rq: rq to move task from
2169
- * @dst_rq: rq to move task to
2170
- *
2171
- * We're holding @rq lock and trying to dispatch a task from @src_rq to
2172
- * @dst_rq's local DSQ and thus need to lock both @src_rq and @dst_rq. Whether
2173
- * @rq stays locked isn't important as long as the state is restored after
2174
- * dispatch_to_local_dsq_unlock().
2175
- */
2176
- static void dispatch_to_local_dsq_lock (struct rq * rq , struct rq * src_rq ,
2177
- struct rq * dst_rq )
2178
- {
2179
- if (src_rq == dst_rq ) {
2180
- raw_spin_rq_unlock (rq );
2181
- raw_spin_rq_lock (dst_rq );
2182
- } else if (rq == src_rq ) {
2183
- double_lock_balance (rq , dst_rq );
2184
- } else if (rq == dst_rq ) {
2185
- double_lock_balance (rq , src_rq );
2186
- } else {
2187
- raw_spin_rq_unlock (rq );
2188
- double_rq_lock (src_rq , dst_rq );
2189
- }
2190
- }
2191
-
2192
- /**
2193
- * dispatch_to_local_dsq_unlock - Undo dispatch_to_local_dsq_lock()
2194
- * @rq: current rq which is locked
2195
- * @src_rq: rq to move task from
2196
- * @dst_rq: rq to move task to
2197
- *
2198
- * Unlock @src_rq and @dst_rq and ensure that @rq is locked on return.
2199
- */
2200
- static void dispatch_to_local_dsq_unlock (struct rq * rq , struct rq * src_rq ,
2201
- struct rq * dst_rq )
2202
- {
2203
- if (src_rq == dst_rq ) {
2204
- raw_spin_rq_unlock (dst_rq );
2205
- raw_spin_rq_lock (rq );
2206
- } else if (rq == src_rq ) {
2207
- double_unlock_balance (rq , dst_rq );
2208
- } else if (rq == dst_rq ) {
2209
- double_unlock_balance (rq , src_rq );
2210
- } else {
2211
- double_rq_unlock (src_rq , dst_rq );
2212
- raw_spin_rq_lock (rq );
2213
- }
2214
- }
2215
2170
#endif /* CONFIG_SMP */
2216
2171
2217
2172
static void consume_local_task (struct rq * rq , struct scx_dispatch_q * dsq ,
@@ -2263,8 +2218,6 @@ static bool task_can_run_on_remote_rq(struct task_struct *p, struct rq *rq)
2263
2218
static bool consume_remote_task (struct rq * rq , struct scx_dispatch_q * dsq ,
2264
2219
struct task_struct * p , struct rq * task_rq )
2265
2220
{
2266
- bool moved = false;
2267
-
2268
2221
lockdep_assert_held (& dsq -> lock ); /* released on return */
2269
2222
2270
2223
/*
@@ -2280,13 +2233,10 @@ static bool consume_remote_task(struct rq *rq, struct scx_dispatch_q *dsq,
2280
2233
p -> scx .holding_cpu = raw_smp_processor_id ();
2281
2234
raw_spin_unlock (& dsq -> lock );
2282
2235
2283
- double_lock_balance (rq , task_rq );
2284
-
2285
- moved = move_task_to_local_dsq (rq , p , 0 );
2286
-
2287
- double_unlock_balance (rq , task_rq );
2236
+ raw_spin_rq_unlock (rq );
2237
+ raw_spin_rq_lock (task_rq );
2288
2238
2289
- return moved ;
2239
+ return move_task_to_local_dsq ( p , 0 , task_rq , rq ) ;
2290
2240
}
2291
2241
#else /* CONFIG_SMP */
2292
2242
static bool task_can_run_on_remote_rq (struct task_struct * p , struct rq * rq ) { return false; }
@@ -2380,7 +2330,6 @@ dispatch_to_local_dsq(struct rq *rq, u64 dsq_id, struct task_struct *p,
2380
2330
2381
2331
#ifdef CONFIG_SMP
2382
2332
if (cpumask_test_cpu (cpu_of (dst_rq ), p -> cpus_ptr )) {
2383
- struct rq * locked_dst_rq = dst_rq ;
2384
2333
bool dsp ;
2385
2334
2386
2335
/*
@@ -2399,7 +2348,11 @@ dispatch_to_local_dsq(struct rq *rq, u64 dsq_id, struct task_struct *p,
2399
2348
/* store_release ensures that dequeue sees the above */
2400
2349
atomic_long_set_release (& p -> scx .ops_state , SCX_OPSS_NONE );
2401
2350
2402
- dispatch_to_local_dsq_lock (rq , src_rq , locked_dst_rq );
2351
+ /* switch to @src_rq lock */
2352
+ if (rq != src_rq ) {
2353
+ raw_spin_rq_unlock (rq );
2354
+ raw_spin_rq_lock (src_rq );
2355
+ }
2403
2356
2404
2357
/*
2405
2358
* We don't require the BPF scheduler to avoid dispatching to
@@ -2426,15 +2379,20 @@ dispatch_to_local_dsq(struct rq *rq, u64 dsq_id, struct task_struct *p,
2426
2379
enq_flags );
2427
2380
}
2428
2381
} else {
2429
- dsp = move_task_to_local_dsq (dst_rq , p , enq_flags );
2382
+ dsp = move_task_to_local_dsq (p , enq_flags ,
2383
+ src_rq , dst_rq );
2430
2384
}
2431
2385
2432
2386
/* if the destination CPU is idle, wake it up */
2433
2387
if (dsp && sched_class_above (p -> sched_class ,
2434
2388
dst_rq -> curr -> sched_class ))
2435
2389
resched_curr (dst_rq );
2436
2390
2437
- dispatch_to_local_dsq_unlock (rq , src_rq , locked_dst_rq );
2391
+ /* switch back to @rq lock */
2392
+ if (rq != dst_rq ) {
2393
+ raw_spin_rq_unlock (dst_rq );
2394
+ raw_spin_rq_lock (rq );
2395
+ }
2438
2396
2439
2397
return dsp ? DTL_DISPATCHED : DTL_LOST ;
2440
2398
}
0 commit comments