pidfile.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. # -*- coding: utf-8 -
  2. #
  3. # This file is part of gunicorn released under the MIT license.
  4. # See the NOTICE for more information.
  5. import errno
  6. import os
  7. import tempfile
  8. class Pidfile(object):
  9. """\
  10. Manage a PID file. If a specific name is provided
  11. it and '"%s.oldpid" % name' will be used. Otherwise
  12. we create a temp file using os.mkstemp.
  13. """
  14. def __init__(self, fname):
  15. self.fname = fname
  16. self.pid = None
  17. def create(self, pid):
  18. oldpid = self.validate()
  19. if oldpid:
  20. if oldpid == os.getpid():
  21. return
  22. msg = "Already running on PID %s (or pid file '%s' is stale)"
  23. raise RuntimeError(msg % (oldpid, self.fname))
  24. self.pid = pid
  25. # Write pidfile
  26. fdir = os.path.dirname(self.fname)
  27. if fdir and not os.path.isdir(fdir):
  28. raise RuntimeError("%s doesn't exist. Can't create pidfile." % fdir)
  29. fd, fname = tempfile.mkstemp(dir=fdir)
  30. os.write(fd, ("%s\n" % self.pid).encode('utf-8'))
  31. if self.fname:
  32. os.rename(fname, self.fname)
  33. else:
  34. self.fname = fname
  35. os.close(fd)
  36. # set permissions to -rw-r--r--
  37. os.chmod(self.fname, 420)
  38. def rename(self, path):
  39. self.unlink()
  40. self.fname = path
  41. self.create(self.pid)
  42. def unlink(self):
  43. """ delete pidfile"""
  44. try:
  45. with open(self.fname, "r") as f:
  46. pid1 = int(f.read() or 0)
  47. if pid1 == self.pid:
  48. os.unlink(self.fname)
  49. except Exception:
  50. pass
  51. def validate(self):
  52. """ Validate pidfile and make it stale if needed"""
  53. if not self.fname:
  54. return
  55. try:
  56. with open(self.fname, "r") as f:
  57. try:
  58. wpid = int(f.read())
  59. except ValueError:
  60. return
  61. try:
  62. os.kill(wpid, 0)
  63. return wpid
  64. except OSError as e:
  65. if e.args[0] == errno.EPERM:
  66. return wpid
  67. if e.args[0] == errno.ESRCH:
  68. return
  69. raise
  70. except IOError as e:
  71. if e.args[0] == errno.ENOENT:
  72. return
  73. raise