Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

timers: Split [try_to_]del_timer[_sync]() to prepare for shutdown mode

Tearing down timers which have circular dependencies to other
functionality, e.g. workqueues, where the timer can schedule work and work
can arm timers, is not trivial.

In those cases it is desired to shutdown the timer in a way which prevents
rearming of the timer. The mechanism to do so is to set timer->function to
NULL and use this as an indicator for the timer arming functions to ignore
the (re)arm request.

Split the inner workings of try_do_del_timer_sync(), del_timer_sync() and
del_timer() into helper functions to prepare for implementing the shutdown
functionality.

No functional change.

Co-developed-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home
Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org
Link: https://lore.kernel.org/r/20221123201625.195147423@linutronix.de

+100 -59
+100 -59
kernel/time/timer.c
··· 1298 1298 EXPORT_SYMBOL_GPL(add_timer_on); 1299 1299 1300 1300 /** 1301 - * timer_delete - Deactivate a timer 1301 + * __timer_delete - Internal function: Deactivate a timer 1302 1302 * @timer: The timer to be deactivated 1303 - * 1304 - * The function only deactivates a pending timer, but contrary to 1305 - * timer_delete_sync() it does not take into account whether the timer's 1306 - * callback function is concurrently executed on a different CPU or not. 1307 - * It neither prevents rearming of the timer. If @timer can be rearmed 1308 - * concurrently then the return value of this function is meaningless. 1309 1303 * 1310 1304 * Return: 1311 1305 * * %0 - The timer was not pending 1312 1306 * * %1 - The timer was pending and deactivated 1313 1307 */ 1314 - int timer_delete(struct timer_list *timer) 1308 + static int __timer_delete(struct timer_list *timer) 1315 1309 { 1316 1310 struct timer_base *base; 1317 1311 unsigned long flags; ··· 1321 1327 1322 1328 return ret; 1323 1329 } 1330 + 1331 + /** 1332 + * timer_delete - Deactivate a timer 1333 + * @timer: The timer to be deactivated 1334 + * 1335 + * The function only deactivates a pending timer, but contrary to 1336 + * timer_delete_sync() it does not take into account whether the timer's 1337 + * callback function is concurrently executed on a different CPU or not. 1338 + * It neither prevents rearming of the timer. If @timer can be rearmed 1339 + * concurrently then the return value of this function is meaningless. 1340 + * 1341 + * Return: 1342 + * * %0 - The timer was not pending 1343 + * * %1 - The timer was pending and deactivated 1344 + */ 1345 + int timer_delete(struct timer_list *timer) 1346 + { 1347 + return __timer_delete(timer); 1348 + } 1324 1349 EXPORT_SYMBOL(timer_delete); 1350 + 1351 + /** 1352 + * __try_to_del_timer_sync - Internal function: Try to deactivate a timer 1353 + * @timer: Timer to deactivate 1354 + * 1355 + * Return: 1356 + * * %0 - The timer was not pending 1357 + * * %1 - The timer was pending and deactivated 1358 + * * %-1 - The timer callback function is running on a different CPU 1359 + */ 1360 + static int __try_to_del_timer_sync(struct timer_list *timer) 1361 + { 1362 + struct timer_base *base; 1363 + unsigned long flags; 1364 + int ret = -1; 1365 + 1366 + debug_assert_init(timer); 1367 + 1368 + base = lock_timer_base(timer, &flags); 1369 + 1370 + if (base->running_timer != timer) 1371 + ret = detach_if_pending(timer, base, true); 1372 + 1373 + raw_spin_unlock_irqrestore(&base->lock, flags); 1374 + 1375 + return ret; 1376 + } 1325 1377 1326 1378 /** 1327 1379 * try_to_del_timer_sync - Try to deactivate a timer ··· 1387 1347 */ 1388 1348 int try_to_del_timer_sync(struct timer_list *timer) 1389 1349 { 1390 - struct timer_base *base; 1391 - unsigned long flags; 1392 - int ret = -1; 1393 - 1394 - debug_assert_init(timer); 1395 - 1396 - base = lock_timer_base(timer, &flags); 1397 - 1398 - if (base->running_timer != timer) 1399 - ret = detach_if_pending(timer, base, true); 1400 - 1401 - raw_spin_unlock_irqrestore(&base->lock, flags); 1402 - 1403 - return ret; 1350 + return __try_to_del_timer_sync(timer); 1404 1351 } 1405 1352 EXPORT_SYMBOL(try_to_del_timer_sync); 1406 1353 ··· 1465 1438 #endif 1466 1439 1467 1440 /** 1441 + * __timer_delete_sync - Internal function: Deactivate a timer and wait 1442 + * for the handler to finish. 1443 + * @timer: The timer to be deactivated 1444 + * 1445 + * Return: 1446 + * * %0 - The timer was not pending 1447 + * * %1 - The timer was pending and deactivated 1448 + */ 1449 + static int __timer_delete_sync(struct timer_list *timer) 1450 + { 1451 + int ret; 1452 + 1453 + #ifdef CONFIG_LOCKDEP 1454 + unsigned long flags; 1455 + 1456 + /* 1457 + * If lockdep gives a backtrace here, please reference 1458 + * the synchronization rules above. 1459 + */ 1460 + local_irq_save(flags); 1461 + lock_map_acquire(&timer->lockdep_map); 1462 + lock_map_release(&timer->lockdep_map); 1463 + local_irq_restore(flags); 1464 + #endif 1465 + /* 1466 + * don't use it in hardirq context, because it 1467 + * could lead to deadlock. 1468 + */ 1469 + WARN_ON(in_hardirq() && !(timer->flags & TIMER_IRQSAFE)); 1470 + 1471 + /* 1472 + * Must be able to sleep on PREEMPT_RT because of the slowpath in 1473 + * del_timer_wait_running(). 1474 + */ 1475 + if (IS_ENABLED(CONFIG_PREEMPT_RT) && !(timer->flags & TIMER_IRQSAFE)) 1476 + lockdep_assert_preemption_enabled(); 1477 + 1478 + do { 1479 + ret = __try_to_del_timer_sync(timer); 1480 + 1481 + if (unlikely(ret < 0)) { 1482 + del_timer_wait_running(timer); 1483 + cpu_relax(); 1484 + } 1485 + } while (ret < 0); 1486 + 1487 + return ret; 1488 + } 1489 + 1490 + /** 1468 1491 * timer_delete_sync - Deactivate a timer and wait for the handler to finish. 1469 1492 * @timer: The timer to be deactivated 1470 1493 * ··· 1555 1478 */ 1556 1479 int timer_delete_sync(struct timer_list *timer) 1557 1480 { 1558 - int ret; 1559 - 1560 - #ifdef CONFIG_LOCKDEP 1561 - unsigned long flags; 1562 - 1563 - /* 1564 - * If lockdep gives a backtrace here, please reference 1565 - * the synchronization rules above. 1566 - */ 1567 - local_irq_save(flags); 1568 - lock_map_acquire(&timer->lockdep_map); 1569 - lock_map_release(&timer->lockdep_map); 1570 - local_irq_restore(flags); 1571 - #endif 1572 - /* 1573 - * don't use it in hardirq context, because it 1574 - * could lead to deadlock. 1575 - */ 1576 - WARN_ON(in_hardirq() && !(timer->flags & TIMER_IRQSAFE)); 1577 - 1578 - /* 1579 - * Must be able to sleep on PREEMPT_RT because of the slowpath in 1580 - * del_timer_wait_running(). 1581 - */ 1582 - if (IS_ENABLED(CONFIG_PREEMPT_RT) && !(timer->flags & TIMER_IRQSAFE)) 1583 - lockdep_assert_preemption_enabled(); 1584 - 1585 - do { 1586 - ret = try_to_del_timer_sync(timer); 1587 - 1588 - if (unlikely(ret < 0)) { 1589 - del_timer_wait_running(timer); 1590 - cpu_relax(); 1591 - } 1592 - } while (ret < 0); 1593 - 1594 - return ret; 1481 + return __timer_delete_sync(timer); 1595 1482 } 1596 1483 EXPORT_SYMBOL(timer_delete_sync); 1597 1484