mycroft-core/mycroft/lock/__init__.py

192 lines
6.5 KiB
Python
Raw Normal View History

Change to Apache 2.0 license from GPLv3.0 This commit officially switches the mycroft-core repository from GPLv3.0 licensing to Apache 2.0. All dependencies on GPL'ed code have been removed and we have contacted all previous contributors with still-existing code in the repository to agree to this change. Going forward, all contributors will sign a Contributor License Agreement (CLA) by visiting https://mycroft.ai/cla, then they will be included in the Mycroft Project's overall Contributor list, found at: https://github.com/MycroftAI/contributors. This cleanly protects the project, the contributor and all who use the technology to build upon. Futher discussion can be found at this blog post: https://mycroft.ai/blog/right-license/ This commit also removes all __author__="" from the code. These lines are painful to maintain and the etiquette surrounding their maintainence is unclear. Do you remove a name from the list if the last line of code the wrote gets replaced? Etc. Now all contributors are publicly acknowledged in the aforementioned repo, and actual authorship is maintained by Github in a much more effective and elegant way! Finally, a few references to "Mycroft AI" were changed to the correct legal entity name "Mycroft AI Inc." ==== Fixed Issues ==== #403 Update License.md and file headers to Apache 2.0 #400 Update LICENSE.md ==== Documentation Notes ==== Deprecated the ScheduledSkill and ScheduledCRUDSkill classes. These capabilities have been superceded by the more flexible MycroftSkill class methods schedule_event(), schedule_repeating_event(), update_event(), and cancel_event().
2017-10-04 06:28:44 +00:00
# Copyright 2017 Mycroft AI Inc.
#
Change to Apache 2.0 license from GPLv3.0 This commit officially switches the mycroft-core repository from GPLv3.0 licensing to Apache 2.0. All dependencies on GPL'ed code have been removed and we have contacted all previous contributors with still-existing code in the repository to agree to this change. Going forward, all contributors will sign a Contributor License Agreement (CLA) by visiting https://mycroft.ai/cla, then they will be included in the Mycroft Project's overall Contributor list, found at: https://github.com/MycroftAI/contributors. This cleanly protects the project, the contributor and all who use the technology to build upon. Futher discussion can be found at this blog post: https://mycroft.ai/blog/right-license/ This commit also removes all __author__="" from the code. These lines are painful to maintain and the etiquette surrounding their maintainence is unclear. Do you remove a name from the list if the last line of code the wrote gets replaced? Etc. Now all contributors are publicly acknowledged in the aforementioned repo, and actual authorship is maintained by Github in a much more effective and elegant way! Finally, a few references to "Mycroft AI" were changed to the correct legal entity name "Mycroft AI Inc." ==== Fixed Issues ==== #403 Update License.md and file headers to Apache 2.0 #400 Update LICENSE.md ==== Documentation Notes ==== Deprecated the ScheduledSkill and ScheduledCRUDSkill classes. These capabilities have been superceded by the more flexible MycroftSkill class methods schedule_event(), schedule_repeating_event(), update_event(), and cancel_event().
2017-10-04 06:28:44 +00:00
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
Change to Apache 2.0 license from GPLv3.0 This commit officially switches the mycroft-core repository from GPLv3.0 licensing to Apache 2.0. All dependencies on GPL'ed code have been removed and we have contacted all previous contributors with still-existing code in the repository to agree to this change. Going forward, all contributors will sign a Contributor License Agreement (CLA) by visiting https://mycroft.ai/cla, then they will be included in the Mycroft Project's overall Contributor list, found at: https://github.com/MycroftAI/contributors. This cleanly protects the project, the contributor and all who use the technology to build upon. Futher discussion can be found at this blog post: https://mycroft.ai/blog/right-license/ This commit also removes all __author__="" from the code. These lines are painful to maintain and the etiquette surrounding their maintainence is unclear. Do you remove a name from the list if the last line of code the wrote gets replaced? Etc. Now all contributors are publicly acknowledged in the aforementioned repo, and actual authorship is maintained by Github in a much more effective and elegant way! Finally, a few references to "Mycroft AI" were changed to the correct legal entity name "Mycroft AI Inc." ==== Fixed Issues ==== #403 Update License.md and file headers to Apache 2.0 #400 Update LICENSE.md ==== Documentation Notes ==== Deprecated the ScheduledSkill and ScheduledCRUDSkill classes. These capabilities have been superceded by the more flexible MycroftSkill class methods schedule_event(), schedule_repeating_event(), update_event(), and cancel_event().
2017-10-04 06:28:44 +00:00
# http://www.apache.org/licenses/LICENSE-2.0
#
Change to Apache 2.0 license from GPLv3.0 This commit officially switches the mycroft-core repository from GPLv3.0 licensing to Apache 2.0. All dependencies on GPL'ed code have been removed and we have contacted all previous contributors with still-existing code in the repository to agree to this change. Going forward, all contributors will sign a Contributor License Agreement (CLA) by visiting https://mycroft.ai/cla, then they will be included in the Mycroft Project's overall Contributor list, found at: https://github.com/MycroftAI/contributors. This cleanly protects the project, the contributor and all who use the technology to build upon. Futher discussion can be found at this blog post: https://mycroft.ai/blog/right-license/ This commit also removes all __author__="" from the code. These lines are painful to maintain and the etiquette surrounding their maintainence is unclear. Do you remove a name from the list if the last line of code the wrote gets replaced? Etc. Now all contributors are publicly acknowledged in the aforementioned repo, and actual authorship is maintained by Github in a much more effective and elegant way! Finally, a few references to "Mycroft AI" were changed to the correct legal entity name "Mycroft AI Inc." ==== Fixed Issues ==== #403 Update License.md and file headers to Apache 2.0 #400 Update LICENSE.md ==== Documentation Notes ==== Deprecated the ScheduledSkill and ScheduledCRUDSkill classes. These capabilities have been superceded by the more flexible MycroftSkill class methods schedule_event(), schedule_repeating_event(), update_event(), and cancel_event().
2017-10-04 06:28:44 +00:00
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2017-04-06 22:56:34 +00:00
#
from signal import getsignal, signal, SIGKILL, SIGINT, SIGTERM, \
SIG_DFL, default_int_handler, SIG_IGN # signals
import os # Operating System functions
2017-04-06 22:56:34 +00:00
#
# Wrapper around chain of handler functions for a specific system level signal.
# Often used to trap Ctrl-C for specific application purposes.
from mycroft.util import LOG
class Signal: # python 3+ class Signal
2017-04-06 22:56:34 +00:00
"""
2017-04-06 22:56:34 +00:00
Capture and replace a signal handler with a user supplied function.
The user supplied function is always called first then the previous
handler, if it exists, will be called. It is possible to chain several
signal handlers together by creating multiply instances of objects of
this class, providing a different user functions for each instance. All
provided user functions will be called in LIFO order.
"""
2017-04-06 22:56:34 +00:00
#
# Constructor
# Get the previous handler function then set the passed function
# as the new handler function for this signal
def __init__(self, sig_value, func):
"""
2017-04-06 22:56:34 +00:00
Create an instance of the signal handler class.
sig_value: The ID value of the signal to be captured.
func: User supplied function that will act as the new signal handler.
"""
2017-04-06 22:56:34 +00:00
super(Signal, self).__init__() # python 3+ 'super().__init__()
self.__sig_value = sig_value
self.__user_func = func # store user passed function
self.__previous_func = signal(sig_value, self)
self.__previous_func = { # Convert signal codes to functions
SIG_DFL: default_int_handler,
SIG_IGN: lambda a, b: None
}.get(self.__previous_func, self.__previous_func)
2017-04-06 22:56:34 +00:00
#
# Called to handle the passed signal
def __call__(self, signame, sf):
"""
2017-04-06 22:56:34 +00:00
Allows the instance of this class to be called as a function.
When called it runs the user supplied signal handler than
checks to see if there is a previously defined handler. If
there is a previously defined handler call it.
"""
self.__user_func()
self.__previous_func(signame, sf)
2017-04-06 22:56:34 +00:00
#
# reset the signal handler
def __del__(self):
"""
2017-04-06 22:56:34 +00:00
Class destructor. Called during garbage collection.
Resets the signal handler to the previous function.
"""
2017-04-06 22:56:34 +00:00
signal(self.__sig_value, self.__previous_func)
# End class Signal
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
#
# Create, delete and manipulate a PID file for this service
2017-04-06 22:56:34 +00:00
# ------------------------------------------------------------------------------
class Lock: # python 3+ 'class Lock'
2017-04-06 22:56:34 +00:00
"""
2017-04-06 22:56:34 +00:00
Create and maintains the PID lock file for this application process.
The PID lock file is located in /tmp/mycroft/*.pid. If another process
of the same type is started, this class will 'attempt' to stop the
previously running process and then change the process ID in the lock file.
"""
2017-04-06 22:56:34 +00:00
#
# Class constants
DIRECTORY = '/tmp/mycroft'
FILE = '/{}.pid'
#
# Constructor
def __init__(self, service):
"""
2017-04-06 22:56:34 +00:00
Builds the instance of this object. Holds the lock until the
object is garbage collected.
service: Text string. The name of the service application
to be locked (ie: skills, voice)
"""
2017-04-06 22:56:34 +00:00
super(Lock, self).__init__() # python 3+ 'super().__init__()'
self.__pid = os.getpid() # PID of this application
self.path = Lock.DIRECTORY + Lock.FILE.format(service)
self.set_handlers() # set signal handlers
self.create()
#
# Reset the signal handlers to the 'delete' function
def set_handlers(self):
"""
2017-04-06 22:56:34 +00:00
Trap both SIGINT and SIGTERM to gracefully clean up PID files
"""
self.__handlers = {SIGINT: Signal(SIGINT, self.delete),
SIGTERM: Signal(SIGTERM, self.delete)}
2017-04-06 22:56:34 +00:00
#
# Check to see if the PID already exists
# If it does exits perform several things:
# Stop the current process
# Delete the exiting file
def exists(self):
"""
2017-04-06 22:56:34 +00:00
Check to see if the PID lock file currently exists. If it does
than send a SIGTERM signal to the process defined by the value
in the lock file. Catch the keyboard interrupt exception to
prevent propagation if stopped by use of Ctrl-C.
"""
2017-04-06 22:56:34 +00:00
if not os.path.isfile(self.path):
return
with open(self.path, 'r') as L:
try:
os.kill(int(L.read()), SIGKILL)
except Exception as E:
pass
#
# Create a lock file for this server process
def touch(self):
"""
2017-04-06 22:56:34 +00:00
If needed, create the '/tmp/mycroft' directory than open the
lock file for writting and store the current process ID (PID)
as text.
"""
2017-04-06 22:56:34 +00:00
if not os.path.exists(Lock.DIRECTORY):
os.makedirs(Lock.DIRECTORY)
with open(self.path, 'w') as L:
L.write('{}'.format(self.__pid))
#
# Create the PID file
def create(self):
"""
2017-04-06 22:56:34 +00:00
Checks to see if a lock file for this service already exists,
if so have it killed. In either case write the process ID of
the current service process to to the existing or newly created
lock file in /tmp/mycroft/
"""
2017-04-06 22:56:34 +00:00
self.exists() # check for current running process
self.touch()
#
# Delete the PID file - but only if it has not been overwritten
# by a duplicate service application
def delete(self, *args):
"""
2017-04-06 22:56:34 +00:00
If the PID lock file contains the PID of this process delete it.
*args: Ignored. Required as this fuction is called as a signel
handler.
"""
try:
with open(self.path, 'r') as L:
pid = int(L.read())
if self.__pid == pid:
os.unlink(self.path)
except IOError:
pass
2017-04-06 22:56:34 +00:00
# End class Lock