V5 Disk space monitoring
Monitor disk availability and take action when the free disk space or
amount of free inode is running low, it is enabled when BB_DISKMON_DIRS
is set.
* Variable meanings(from meta-yocto/conf/local.conf.sample):
# Set the directories to monitor for disk usage, if more than one
# directories are mounted in the same device, then only one directory
# would be monitored since the monitor is based on the device.
# The format is:
# "action,directory,minimum_space,minimum_free_inode"
#
# The "action" must be set and should be one of:
# ABORT: Immediately abort
# STOPTASKS: The new tasks can't be executed any more, will stop the build
# when the running tasks have been done.
# WARN: show warnings (see BB_DISKMON_WARNINTERVAL for more information)
#
# The "directory" must be set, any directory is OK.
#
# Either "minimum_space" or "minimum_free_inode" (or both of them)
# should be set, otherwise the monitor would not be enabled,
# the unit can be G, M, K or none, but do NOT use GB, MB or KB
# (B is not needed).
#BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
#
# Set disk space and inode interval (only works when the action is "WARN",
# the unit can be G, M, or K, but do NOT use the GB, MB or KB
# (B is not needed), the format is:
# "disk_space_interval, disk_inode_interval", the default value is
# "50M,5K" which means that it would warn when the free space is
# lower than the minimum space(or inode), and would repeat the action
# when the disk space reduces 50M (or the amount of inode reduces 5k)
# again.
#BB_DISKMON_WARNINTERVAL = "50M,5K"
[YOCTO #1589]
(Bitbake rev: 4d173d441d2beb8e6492b6b1842682f8cf32e6cc)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-26 08:48:15 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# ex:ts=4:sw=4:sts=4:et
|
|
|
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
|
|
#
|
|
|
|
# Copyright (C) 2012 Robert Yang
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
|
|
# published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along
|
|
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
|
|
|
import os, logging, re, sys
|
|
|
|
import bb
|
|
|
|
logger = logging.getLogger("BitBake.Monitor")
|
|
|
|
|
|
|
|
def printErr(info):
|
|
|
|
logger.error("%s\n Disk space monitor will NOT be enabled" % info)
|
|
|
|
|
|
|
|
def convertGMK(unit):
|
|
|
|
|
|
|
|
""" Convert the space unit G, M, K, the unit is case-insensitive """
|
|
|
|
|
|
|
|
unitG = re.match('([1-9][0-9]*)[gG]\s?$', unit)
|
|
|
|
if unitG:
|
|
|
|
return int(unitG.group(1)) * (1024 ** 3)
|
|
|
|
unitM = re.match('([1-9][0-9]*)[mM]\s?$', unit)
|
|
|
|
if unitM:
|
|
|
|
return int(unitM.group(1)) * (1024 ** 2)
|
|
|
|
unitK = re.match('([1-9][0-9]*)[kK]\s?$', unit)
|
|
|
|
if unitK:
|
|
|
|
return int(unitK.group(1)) * 1024
|
|
|
|
unitN = re.match('([1-9][0-9]*)\s?$', unit)
|
|
|
|
if unitN:
|
|
|
|
return int(unitN.group(1))
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def getMountedDev(path):
|
|
|
|
|
|
|
|
""" Get the device mounted at the path, uses /proc/mounts """
|
|
|
|
|
|
|
|
# Get the mount point of the filesystem containing path
|
|
|
|
# st_dev is the ID of device containing file
|
|
|
|
parentDev = os.stat(path).st_dev
|
|
|
|
currentDev = parentDev
|
|
|
|
# When the current directory's device is different from the
|
|
|
|
# parrent's, then the current directory is a mount point
|
|
|
|
while parentDev == currentDev:
|
|
|
|
mountPoint = path
|
|
|
|
# Use dirname to get the parrent's directory
|
|
|
|
path = os.path.dirname(path)
|
|
|
|
# Reach the "/"
|
|
|
|
if path == mountPoint:
|
|
|
|
break
|
|
|
|
parentDev= os.stat(path).st_dev
|
|
|
|
|
|
|
|
try:
|
|
|
|
with open("/proc/mounts", "r") as ifp:
|
|
|
|
for line in ifp:
|
|
|
|
procLines = line.rstrip('\n').split()
|
|
|
|
if procLines[1] == mountPoint:
|
|
|
|
return procLines[0]
|
|
|
|
except EnvironmentError:
|
|
|
|
pass
|
|
|
|
return None
|
|
|
|
|
|
|
|
def getDiskData(BBDirs, configuration):
|
|
|
|
|
|
|
|
"""Prepare disk data for disk space monitor"""
|
|
|
|
|
|
|
|
# Save the device IDs, need the ID to be unique (the dictionary's key is
|
|
|
|
# unique), so that when more than one directories are located in the same
|
|
|
|
# device, we just monitor it once
|
|
|
|
devDict = {}
|
|
|
|
for pathSpaceInode in BBDirs.split():
|
|
|
|
# The input format is: "dir,space,inode", dir is a must, space
|
|
|
|
# and inode are optional
|
|
|
|
pathSpaceInodeRe = re.match('([^,]*),([^,]*),([^,]*),?(.*)', pathSpaceInode)
|
|
|
|
if not pathSpaceInodeRe:
|
|
|
|
printErr("Invalid value in BB_DISKMON_DIRS: %s" % pathSpaceInode)
|
|
|
|
return None
|
|
|
|
|
|
|
|
action = pathSpaceInodeRe.group(1)
|
|
|
|
if action not in ("ABORT", "STOPTASKS", "WARN"):
|
|
|
|
printErr("Unknown disk space monitor action: %s" % action)
|
|
|
|
return None
|
|
|
|
|
|
|
|
path = os.path.realpath(pathSpaceInodeRe.group(2))
|
|
|
|
if not path:
|
|
|
|
printErr("Invalid path value in BB_DISKMON_DIRS: %s" % pathSpaceInode)
|
|
|
|
return None
|
|
|
|
|
|
|
|
# The disk space or inode is optional, but it should have a correct
|
|
|
|
# value once it is specified
|
|
|
|
minSpace = pathSpaceInodeRe.group(3)
|
|
|
|
if minSpace:
|
|
|
|
minSpace = convertGMK(minSpace)
|
|
|
|
if not minSpace:
|
|
|
|
printErr("Invalid disk space value in BB_DISKMON_DIRS: %s" % pathSpaceInodeRe.group(3))
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
# 0 means that it is not specified
|
|
|
|
minSpace = None
|
|
|
|
|
|
|
|
minInode = pathSpaceInodeRe.group(4)
|
|
|
|
if minInode:
|
|
|
|
minInode = convertGMK(minInode)
|
|
|
|
if not minInode:
|
|
|
|
printErr("Invalid inode value in BB_DISKMON_DIRS: %s" % pathSpaceInodeRe.group(4))
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
# 0 means that it is not specified
|
|
|
|
minInode = None
|
|
|
|
|
|
|
|
if minSpace is None and minInode is None:
|
|
|
|
printErr("No disk space or inode value in found BB_DISKMON_DIRS: %s" % pathSpaceInode)
|
|
|
|
return None
|
|
|
|
# mkdir for the directory since it may not exist, for example the
|
|
|
|
# DL_DIR may not exist at the very beginning
|
|
|
|
if not os.path.exists(path):
|
|
|
|
bb.utils.mkdirhier(path)
|
|
|
|
mountedDev = getMountedDev(path)
|
|
|
|
devDict[mountedDev] = action, path, minSpace, minInode
|
|
|
|
|
|
|
|
return devDict
|
|
|
|
|
|
|
|
def getInterval(configuration):
|
|
|
|
|
|
|
|
""" Get the disk space interval """
|
|
|
|
|
2012-04-05 12:58:57 +00:00
|
|
|
# The default value is 50M and 5K.
|
|
|
|
spaceDefault = 50 * 1024 * 1024
|
|
|
|
inodeDefault = 5 * 1024
|
|
|
|
|
2012-03-03 10:41:41 +00:00
|
|
|
interval = configuration.getVar("BB_DISKMON_WARNINTERVAL", True)
|
V5 Disk space monitoring
Monitor disk availability and take action when the free disk space or
amount of free inode is running low, it is enabled when BB_DISKMON_DIRS
is set.
* Variable meanings(from meta-yocto/conf/local.conf.sample):
# Set the directories to monitor for disk usage, if more than one
# directories are mounted in the same device, then only one directory
# would be monitored since the monitor is based on the device.
# The format is:
# "action,directory,minimum_space,minimum_free_inode"
#
# The "action" must be set and should be one of:
# ABORT: Immediately abort
# STOPTASKS: The new tasks can't be executed any more, will stop the build
# when the running tasks have been done.
# WARN: show warnings (see BB_DISKMON_WARNINTERVAL for more information)
#
# The "directory" must be set, any directory is OK.
#
# Either "minimum_space" or "minimum_free_inode" (or both of them)
# should be set, otherwise the monitor would not be enabled,
# the unit can be G, M, K or none, but do NOT use GB, MB or KB
# (B is not needed).
#BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
#
# Set disk space and inode interval (only works when the action is "WARN",
# the unit can be G, M, or K, but do NOT use the GB, MB or KB
# (B is not needed), the format is:
# "disk_space_interval, disk_inode_interval", the default value is
# "50M,5K" which means that it would warn when the free space is
# lower than the minimum space(or inode), and would repeat the action
# when the disk space reduces 50M (or the amount of inode reduces 5k)
# again.
#BB_DISKMON_WARNINTERVAL = "50M,5K"
[YOCTO #1589]
(Bitbake rev: 4d173d441d2beb8e6492b6b1842682f8cf32e6cc)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-26 08:48:15 +00:00
|
|
|
if not interval:
|
2012-04-05 12:58:57 +00:00
|
|
|
return spaceDefault, inodeDefault
|
V5 Disk space monitoring
Monitor disk availability and take action when the free disk space or
amount of free inode is running low, it is enabled when BB_DISKMON_DIRS
is set.
* Variable meanings(from meta-yocto/conf/local.conf.sample):
# Set the directories to monitor for disk usage, if more than one
# directories are mounted in the same device, then only one directory
# would be monitored since the monitor is based on the device.
# The format is:
# "action,directory,minimum_space,minimum_free_inode"
#
# The "action" must be set and should be one of:
# ABORT: Immediately abort
# STOPTASKS: The new tasks can't be executed any more, will stop the build
# when the running tasks have been done.
# WARN: show warnings (see BB_DISKMON_WARNINTERVAL for more information)
#
# The "directory" must be set, any directory is OK.
#
# Either "minimum_space" or "minimum_free_inode" (or both of them)
# should be set, otherwise the monitor would not be enabled,
# the unit can be G, M, K or none, but do NOT use GB, MB or KB
# (B is not needed).
#BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
#
# Set disk space and inode interval (only works when the action is "WARN",
# the unit can be G, M, or K, but do NOT use the GB, MB or KB
# (B is not needed), the format is:
# "disk_space_interval, disk_inode_interval", the default value is
# "50M,5K" which means that it would warn when the free space is
# lower than the minimum space(or inode), and would repeat the action
# when the disk space reduces 50M (or the amount of inode reduces 5k)
# again.
#BB_DISKMON_WARNINTERVAL = "50M,5K"
[YOCTO #1589]
(Bitbake rev: 4d173d441d2beb8e6492b6b1842682f8cf32e6cc)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-26 08:48:15 +00:00
|
|
|
else:
|
|
|
|
# The disk space or inode interval is optional, but it should
|
|
|
|
# have a correct value once it is specified
|
|
|
|
intervalRe = re.match('([^,]*),?\s*(.*)', interval)
|
|
|
|
if intervalRe:
|
|
|
|
intervalSpace = intervalRe.group(1)
|
|
|
|
if intervalSpace:
|
|
|
|
intervalSpace = convertGMK(intervalSpace)
|
|
|
|
if not intervalSpace:
|
|
|
|
printErr("Invalid disk space interval value in BB_DISKMON_WARNINTERVAL: %s" % intervalRe.group(1))
|
|
|
|
return None, None
|
2012-04-05 12:58:57 +00:00
|
|
|
else:
|
|
|
|
intervalSpace = spaceDefault
|
V5 Disk space monitoring
Monitor disk availability and take action when the free disk space or
amount of free inode is running low, it is enabled when BB_DISKMON_DIRS
is set.
* Variable meanings(from meta-yocto/conf/local.conf.sample):
# Set the directories to monitor for disk usage, if more than one
# directories are mounted in the same device, then only one directory
# would be monitored since the monitor is based on the device.
# The format is:
# "action,directory,minimum_space,minimum_free_inode"
#
# The "action" must be set and should be one of:
# ABORT: Immediately abort
# STOPTASKS: The new tasks can't be executed any more, will stop the build
# when the running tasks have been done.
# WARN: show warnings (see BB_DISKMON_WARNINTERVAL for more information)
#
# The "directory" must be set, any directory is OK.
#
# Either "minimum_space" or "minimum_free_inode" (or both of them)
# should be set, otherwise the monitor would not be enabled,
# the unit can be G, M, K or none, but do NOT use GB, MB or KB
# (B is not needed).
#BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
#
# Set disk space and inode interval (only works when the action is "WARN",
# the unit can be G, M, or K, but do NOT use the GB, MB or KB
# (B is not needed), the format is:
# "disk_space_interval, disk_inode_interval", the default value is
# "50M,5K" which means that it would warn when the free space is
# lower than the minimum space(or inode), and would repeat the action
# when the disk space reduces 50M (or the amount of inode reduces 5k)
# again.
#BB_DISKMON_WARNINTERVAL = "50M,5K"
[YOCTO #1589]
(Bitbake rev: 4d173d441d2beb8e6492b6b1842682f8cf32e6cc)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-26 08:48:15 +00:00
|
|
|
intervalInode = intervalRe.group(2)
|
|
|
|
if intervalInode:
|
|
|
|
intervalInode = convertGMK(intervalInode)
|
|
|
|
if not intervalInode:
|
|
|
|
printErr("Invalid disk inode interval value in BB_DISKMON_WARNINTERVAL: %s" % intervalRe.group(2))
|
|
|
|
return None, None
|
2012-04-05 12:58:57 +00:00
|
|
|
else:
|
|
|
|
intervalInode = inodeDefault
|
V5 Disk space monitoring
Monitor disk availability and take action when the free disk space or
amount of free inode is running low, it is enabled when BB_DISKMON_DIRS
is set.
* Variable meanings(from meta-yocto/conf/local.conf.sample):
# Set the directories to monitor for disk usage, if more than one
# directories are mounted in the same device, then only one directory
# would be monitored since the monitor is based on the device.
# The format is:
# "action,directory,minimum_space,minimum_free_inode"
#
# The "action" must be set and should be one of:
# ABORT: Immediately abort
# STOPTASKS: The new tasks can't be executed any more, will stop the build
# when the running tasks have been done.
# WARN: show warnings (see BB_DISKMON_WARNINTERVAL for more information)
#
# The "directory" must be set, any directory is OK.
#
# Either "minimum_space" or "minimum_free_inode" (or both of them)
# should be set, otherwise the monitor would not be enabled,
# the unit can be G, M, K or none, but do NOT use GB, MB or KB
# (B is not needed).
#BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
#
# Set disk space and inode interval (only works when the action is "WARN",
# the unit can be G, M, or K, but do NOT use the GB, MB or KB
# (B is not needed), the format is:
# "disk_space_interval, disk_inode_interval", the default value is
# "50M,5K" which means that it would warn when the free space is
# lower than the minimum space(or inode), and would repeat the action
# when the disk space reduces 50M (or the amount of inode reduces 5k)
# again.
#BB_DISKMON_WARNINTERVAL = "50M,5K"
[YOCTO #1589]
(Bitbake rev: 4d173d441d2beb8e6492b6b1842682f8cf32e6cc)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-26 08:48:15 +00:00
|
|
|
return intervalSpace, intervalInode
|
|
|
|
else:
|
|
|
|
printErr("Invalid interval value in BB_DISKMON_WARNINTERVAL: %s" % interval)
|
|
|
|
return None, None
|
|
|
|
|
|
|
|
class diskMonitor:
|
|
|
|
|
|
|
|
"""Prepare the disk space monitor data"""
|
|
|
|
|
|
|
|
def __init__(self, configuration):
|
|
|
|
|
|
|
|
self.enableMonitor = False
|
|
|
|
|
2012-03-03 10:41:41 +00:00
|
|
|
BBDirs = configuration.getVar("BB_DISKMON_DIRS", True) or None
|
V5 Disk space monitoring
Monitor disk availability and take action when the free disk space or
amount of free inode is running low, it is enabled when BB_DISKMON_DIRS
is set.
* Variable meanings(from meta-yocto/conf/local.conf.sample):
# Set the directories to monitor for disk usage, if more than one
# directories are mounted in the same device, then only one directory
# would be monitored since the monitor is based on the device.
# The format is:
# "action,directory,minimum_space,minimum_free_inode"
#
# The "action" must be set and should be one of:
# ABORT: Immediately abort
# STOPTASKS: The new tasks can't be executed any more, will stop the build
# when the running tasks have been done.
# WARN: show warnings (see BB_DISKMON_WARNINTERVAL for more information)
#
# The "directory" must be set, any directory is OK.
#
# Either "minimum_space" or "minimum_free_inode" (or both of them)
# should be set, otherwise the monitor would not be enabled,
# the unit can be G, M, K or none, but do NOT use GB, MB or KB
# (B is not needed).
#BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
#
# Set disk space and inode interval (only works when the action is "WARN",
# the unit can be G, M, or K, but do NOT use the GB, MB or KB
# (B is not needed), the format is:
# "disk_space_interval, disk_inode_interval", the default value is
# "50M,5K" which means that it would warn when the free space is
# lower than the minimum space(or inode), and would repeat the action
# when the disk space reduces 50M (or the amount of inode reduces 5k)
# again.
#BB_DISKMON_WARNINTERVAL = "50M,5K"
[YOCTO #1589]
(Bitbake rev: 4d173d441d2beb8e6492b6b1842682f8cf32e6cc)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-26 08:48:15 +00:00
|
|
|
if BBDirs:
|
|
|
|
self.devDict = getDiskData(BBDirs, configuration)
|
|
|
|
if self.devDict:
|
|
|
|
self.spaceInterval, self.inodeInterval = getInterval(configuration)
|
|
|
|
if self.spaceInterval and self.inodeInterval:
|
|
|
|
self.enableMonitor = True
|
|
|
|
# These are for saving the previous disk free space and inode, we
|
|
|
|
# use them to avoid print too many warning messages
|
|
|
|
self.preFreeS = {}
|
|
|
|
self.preFreeI = {}
|
|
|
|
# This is for STOPTASKS and ABORT, to avoid print the message repeatly
|
|
|
|
# during waiting the tasks to finish
|
|
|
|
self.checked = {}
|
|
|
|
for dev in self.devDict:
|
|
|
|
self.preFreeS[dev] = 0
|
|
|
|
self.preFreeI[dev] = 0
|
|
|
|
self.checked[dev] = False
|
|
|
|
if self.spaceInterval is None and self.inodeInterval is None:
|
|
|
|
self.enableMonitor = False
|
|
|
|
|
|
|
|
def check(self, rq):
|
|
|
|
|
|
|
|
""" Take action for the monitor """
|
|
|
|
|
|
|
|
if self.enableMonitor:
|
|
|
|
for dev in self.devDict:
|
|
|
|
st = os.statvfs(self.devDict[dev][1])
|
|
|
|
|
|
|
|
# The free space, float point number
|
|
|
|
freeSpace = st.f_bavail * st.f_frsize
|
|
|
|
|
|
|
|
if self.devDict[dev][2] and freeSpace < self.devDict[dev][2]:
|
|
|
|
# Always show warning, the self.checked would always be False if the action is WARN
|
|
|
|
if self.preFreeS[dev] == 0 or self.preFreeS[dev] - freeSpace > self.spaceInterval and not self.checked[dev]:
|
|
|
|
logger.warn("The free space of %s is running low (%.3fGB left)" % (dev, freeSpace / 1024 / 1024 / 1024.0))
|
|
|
|
self.preFreeS[dev] = freeSpace
|
|
|
|
|
|
|
|
if self.devDict[dev][0] == "STOPTASKS" and not self.checked[dev]:
|
|
|
|
logger.error("No new tasks can be excuted since the disk space monitor action is \"STOPTASKS\"!")
|
|
|
|
self.checked[dev] = True
|
|
|
|
rq.finish_runqueue(False)
|
|
|
|
elif self.devDict[dev][0] == "ABORT" and not self.checked[dev]:
|
|
|
|
logger.error("Immediately abort since the disk space monitor action is \"ABORT\"!")
|
|
|
|
self.checked[dev] = True
|
|
|
|
rq.finish_runqueue(True)
|
|
|
|
|
|
|
|
# The free inodes, float point number
|
|
|
|
freeInode = st.f_favail
|
|
|
|
|
|
|
|
if self.devDict[dev][3] and freeInode < self.devDict[dev][3]:
|
|
|
|
# Always show warning, the self.checked would always be False if the action is WARN
|
|
|
|
if self.preFreeI[dev] == 0 or self.preFreeI[dev] - freeInode > self.inodeInterval and not self.checked[dev]:
|
|
|
|
logger.warn("The free inode of %s is running low (%.3fK left)" % (dev, freeInode / 1024.0))
|
|
|
|
self.preFreeI[dev] = freeInode
|
|
|
|
|
|
|
|
if self.devDict[dev][0] == "STOPTASKS" and not self.checked[dev]:
|
|
|
|
logger.error("No new tasks can be excuted since the disk space monitor action is \"STOPTASKS\"!")
|
|
|
|
self.checked[dev] = True
|
|
|
|
rq.finish_runqueue(False)
|
|
|
|
elif self.devDict[dev][0] == "ABORT" and not self.checked[dev]:
|
|
|
|
logger.error("Immediately abort since the disk space monitor action is \"ABORT\"!")
|
|
|
|
self.checked[dev] = True
|
|
|
|
rq.finish_runqueue(True)
|
|
|
|
return
|