Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
966f7dfa
Commit
966f7dfa
authored
Jul 24, 2016
by
Hanno Schlichting
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
flake8
parent
8e52f973
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
111 additions
and
108 deletions
+111
-108
src/Lifetime/__init__.py
src/Lifetime/__init__.py
+13
-10
src/Signals/SignalHandler.py
src/Signals/SignalHandler.py
+8
-4
src/Signals/Signals.py
src/Signals/Signals.py
+14
-9
src/Signals/WinSignalHandler.py
src/Signals/WinSignalHandler.py
+38
-34
src/Signals/__init__.py
src/Signals/__init__.py
+0
-3
src/Signals/threads.py
src/Signals/threads.py
+4
-4
src/Zope2/Startup/__init__.py
src/Zope2/Startup/__init__.py
+13
-16
src/Zope2/Startup/tests/testStarter.py
src/Zope2/Startup/tests/testStarter.py
+21
-28
No files found.
src/Lifetime/__init__.py
View file @
966f7dfa
import
sys
,
asyncore
,
time
import
asyncore
import
time
_shutdown_phase
=
0
_shutdown_phase
=
0
_shutdown_timeout
=
30
# seconds per phase
_shutdown_timeout
=
30
# seconds per phase
# The shutdown phase counts up from 0 to 4.
# The shutdown phase counts up from 0 to 4.
#
#
...
@@ -23,7 +24,8 @@ _shutdown_timeout = 30 # seconds per phase
...
@@ -23,7 +24,8 @@ _shutdown_timeout = 30 # seconds per phase
# of time that it has currently been in that phase. This method should return
# of time that it has currently been in that phase. This method should return
# true if it does not yet want shutdown to proceed to the next phase.
# true if it does not yet want shutdown to proceed to the next phase.
def
shutdown
(
exit_code
,
fast
=
0
):
def
shutdown
(
exit_code
,
fast
=
0
):
global
_shutdown_phase
global
_shutdown_phase
global
_shutdown_timeout
global
_shutdown_timeout
if
_shutdown_phase
==
0
:
if
_shutdown_phase
==
0
:
...
@@ -38,6 +40,7 @@ def shutdown(exit_code,fast = 0):
...
@@ -38,6 +40,7 @@ def shutdown(exit_code,fast = 0):
# enough, but still clean.
# enough, but still clean.
_shutdown_timeout
=
1.0
_shutdown_timeout
=
1.0
def
loop
():
def
loop
():
# Run the main loop until someone calls shutdown()
# Run the main loop until someone calls shutdown()
lifetime_loop
()
lifetime_loop
()
...
@@ -45,6 +48,7 @@ def loop():
...
@@ -45,6 +48,7 @@ def loop():
# loop to allow remaining requests to trickle away.
# loop to allow remaining requests to trickle away.
graceful_shutdown_loop
()
graceful_shutdown_loop
()
def
lifetime_loop
():
def
lifetime_loop
():
# The main loop. Stay in here until we need to shutdown
# The main loop. Stay in here until we need to shutdown
map
=
asyncore
.
socket_map
map
=
asyncore
.
socket_map
...
@@ -52,7 +56,7 @@ def lifetime_loop():
...
@@ -52,7 +56,7 @@ def lifetime_loop():
while
map
and
_shutdown_phase
==
0
:
while
map
and
_shutdown_phase
==
0
:
asyncore
.
poll
(
timeout
,
map
)
asyncore
.
poll
(
timeout
,
map
)
def
graceful_shutdown_loop
():
def
graceful_shutdown_loop
():
# The shutdown loop. Allow various services to shutdown gradually.
# The shutdown loop. Allow various services to shutdown gradually.
global
_shutdown_phase
global
_shutdown_phase
...
@@ -60,19 +64,19 @@ def graceful_shutdown_loop():
...
@@ -60,19 +64,19 @@ def graceful_shutdown_loop():
timeout
=
1.0
timeout
=
1.0
map
=
asyncore
.
socket_map
map
=
asyncore
.
socket_map
while
map
and
_shutdown_phase
<
4
:
while
map
and
_shutdown_phase
<
4
:
time_in_this_phase
=
time
.
time
()
-
timestamp
time_in_this_phase
=
time
.
time
()
-
timestamp
veto
=
0
veto
=
0
for
fd
,
obj
in
map
.
items
():
for
fd
,
obj
in
map
.
items
():
try
:
try
:
fn
=
getattr
(
obj
,
'clean_shutdown_control'
)
fn
=
getattr
(
obj
,
'clean_shutdown_control'
)
except
AttributeError
:
except
AttributeError
:
pass
pass
else
:
else
:
try
:
try
:
veto
=
veto
or
fn
(
_shutdown_phase
,
time_in_this_phase
)
veto
=
veto
or
fn
(
_shutdown_phase
,
time_in_this_phase
)
except
:
except
:
obj
.
handle_error
()
obj
.
handle_error
()
if
veto
and
time_in_this_phase
<
_shutdown_timeout
:
if
veto
and
time_in_this_phase
<
_shutdown_timeout
:
# Any open socket handler can veto moving on to the next shutdown
# Any open socket handler can veto moving on to the next shutdown
# phase. (but not forever)
# phase. (but not forever)
asyncore
.
poll
(
timeout
,
map
)
asyncore
.
poll
(
timeout
,
map
)
...
@@ -80,4 +84,3 @@ def graceful_shutdown_loop():
...
@@ -80,4 +84,3 @@ def graceful_shutdown_loop():
# No vetos? That is one step closer to shutting down
# No vetos? That is one step closer to shutting down
_shutdown_phase
+=
1
_shutdown_phase
+=
1
timestamp
=
time
.
time
()
timestamp
=
time
.
time
()
src/Signals/SignalHandler.py
View file @
966f7dfa
...
@@ -12,13 +12,15 @@
...
@@ -12,13 +12,15 @@
##############################################################################
##############################################################################
"""Signal handling dispatcher."""
"""Signal handling dispatcher."""
import
sys
,
os
import
os
import
sys
import
signal
import
signal
from
logging
import
getLogger
from
logging
import
getLogger
LOG
=
getLogger
(
'SignalHandler'
)
LOG
=
getLogger
(
'SignalHandler'
)
class
SignalHandler
:
class
SignalHandler
(
object
):
def
__init__
(
self
):
def
__init__
(
self
):
self
.
registry
=
{}
self
.
registry
=
{}
...
@@ -52,7 +54,8 @@ class SignalHandler:
...
@@ -52,7 +54,8 @@ class SignalHandler:
for
handler
in
self
.
registry
.
get
(
signum
,
[]):
for
handler
in
self
.
registry
.
get
(
signum
,
[]):
# Never let a bad handler prevent the standard signal
# Never let a bad handler prevent the standard signal
# handlers from running.
# handlers from running.
try
:
handler
()
try
:
handler
()
except
SystemExit
:
except
SystemExit
:
# if we trap SystemExit, we can't restart
# if we trap SystemExit, we can't restart
raise
raise
...
@@ -62,6 +65,7 @@ class SignalHandler:
...
@@ -62,6 +65,7 @@ class SignalHandler:
_signals
=
None
_signals
=
None
def
get_signal_name
(
n
):
def
get_signal_name
(
n
):
"""Return the symbolic name for signal n.
"""Return the symbolic name for signal n.
...
...
src/Signals/Signals.py
View file @
966f7dfa
...
@@ -22,7 +22,6 @@ import Lifetime
...
@@ -22,7 +22,6 @@ import Lifetime
from
.threads
import
dump_threads
from
.threads
import
dump_threads
logger
=
logging
.
getLogger
(
"Z2"
)
logger
=
logging
.
getLogger
(
"Z2"
)
if
os
.
name
==
'nt'
:
if
os
.
name
==
'nt'
:
...
@@ -37,11 +36,12 @@ if os.name == 'nt':
...
@@ -37,11 +36,12 @@ if os.name == 'nt':
else
:
else
:
from
SignalHandler
import
SignalHandler
from
SignalHandler
import
SignalHandler
def
shutdownFastHandler
():
def
shutdownFastHandler
():
"""Shutdown cleanly on SIGTERM. This is registered first,
"""Shutdown cleanly on SIGTERM. This is registered first,
so it should be called after all other handlers."""
so it should be called after all other handlers."""
logger
.
info
(
"Shutting down fast"
)
logger
.
info
(
"Shutting down fast"
)
Lifetime
.
shutdown
(
0
,
fast
=
1
)
Lifetime
.
shutdown
(
0
,
fast
=
1
)
def
shutdownHandler
():
def
shutdownHandler
():
...
@@ -50,6 +50,7 @@ def shutdownHandler():
...
@@ -50,6 +50,7 @@ def shutdownHandler():
logger
.
info
(
"Shutting down"
)
logger
.
info
(
"Shutting down"
)
sys
.
exit
(
0
)
sys
.
exit
(
0
)
def
restartHandler
():
def
restartHandler
():
"""Restart cleanly on SIGHUP. This is registered first, so it
"""Restart cleanly on SIGHUP. This is registered first, so it
should be called after all other SIGHUP handlers."""
should be called after all other SIGHUP handlers."""
...
@@ -59,11 +60,11 @@ def restartHandler():
...
@@ -59,11 +60,11 @@ def restartHandler():
def
showStacks
():
def
showStacks
():
"""Dump a stracktrace of all threads on the console."""
"""Dump a stracktrace of all threads on the console."""
print
dump_threads
(
)
print
(
dump_threads
()
)
sys
.
stdout
.
flush
()
sys
.
stdout
.
flush
()
class
LogfileReopenHandler
:
class
LogfileReopenHandler
(
object
)
:
"""Reopen log files on SIGUSR2.
"""Reopen log files on SIGUSR2.
This is registered first, so it should be called after all other
This is registered first, so it should be called after all other
...
@@ -77,12 +78,15 @@ class LogfileReopenHandler:
...
@@ -77,12 +78,15 @@ class LogfileReopenHandler:
log
.
reopen
()
log
.
reopen
()
logger
.
info
(
"Log files reopened successfully"
)
logger
.
info
(
"Log files reopened successfully"
)
# On Windows, a 'reopen' is useless - the file can not be renamed
# On Windows, a 'reopen' is useless - the file can not be renamed
# while open, so we perform a trivial 'rotate'.
# while open, so we perform a trivial 'rotate'.
class
LogfileRotateHandler
:
class
LogfileRotateHandler
(
object
):
"""Rotate log files on SIGUSR2. Only called on Windows. This is
"""
registered first, so it should be called after all other SIGUSR2
Rotate log files on SIGUSR2. Only called on Windows. This is
handlers."""
registered first, so it should be called after all other SIGUSR2
handlers.
"""
def
__init__
(
self
,
loggers
):
def
__init__
(
self
,
loggers
):
self
.
loggers
=
[
log
for
log
in
loggers
if
log
is
not
None
]
self
.
loggers
=
[
log
for
log
in
loggers
if
log
is
not
None
]
...
@@ -95,6 +99,7 @@ class LogfileRotateHandler:
...
@@ -95,6 +99,7 @@ class LogfileRotateHandler:
handler
.
rotate
()
handler
.
rotate
()
logger
.
info
(
"Log files rotation complete"
)
logger
.
info
(
"Log files rotation complete"
)
def
registerZopeSignals
(
loggers
):
def
registerZopeSignals
(
loggers
):
from
signal
import
SIGTERM
,
SIGINT
from
signal
import
SIGTERM
,
SIGINT
try
:
try
:
...
@@ -111,7 +116,7 @@ def registerZopeSignals(loggers):
...
@@ -111,7 +116,7 @@ def registerZopeSignals(loggers):
mod_wsgi
=
True
mod_wsgi
=
True
try
:
try
:
from
mod_wsgi
import
version
from
mod_wsgi
import
version
# NOQA
except
ImportError
:
except
ImportError
:
mod_wsgi
=
False
mod_wsgi
=
False
...
...
src/Signals/WinSignalHandler.py
View file @
966f7dfa
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
#
#
# One event is used per signal, and the event name is based on both the
# One event is used per signal, and the event name is based on both the
# Zope process ID and the signal number. For example, assuming a process
# Zope process ID and the signal number. For example, assuming a process
# ID of 123, a SIGINT handler would create an event called "Zope-123-2"
# ID of 123, a SIGINT handler would create an event called "Zope-123-2"
# (as signal.SIGINT==2). The logfile reopen handler uses an event named
# (as signal.SIGINT==2). The logfile reopen handler uses an event named
# "Zope-123-12" (as the logfile handler uses SIGUSR2, which == 12)
# "Zope-123-12" (as the logfile handler uses SIGUSR2, which == 12)
...
@@ -35,13 +35,14 @@
...
@@ -35,13 +35,14 @@
# NOTE: There is one huge semantic difference between these "signals"
# NOTE: There is one huge semantic difference between these "signals"
# and signals on Unix. On Windows, the signals are delivered asynchronously
# and signals on Unix. On Windows, the signals are delivered asynchronously
# to a thread inside this module. This thread calls the event handler
# to a thread inside this module. This thread calls the event handler
# directly - there is no magic to switch the call back to the main thread.
# directly - there is no magic to switch the call back to the main thread.
# If this is a problem (not currently, but likely later), one option may be
# If this is a problem (not currently, but likely later), one option may be
# to add yet another asyncore handler - the thread in this module could
# to add yet another asyncore handler - the thread in this module could
# then "post" the request to the main thread via this asyncore handler.
# then "post" the request to the main thread via this asyncore handler.
import
sys
,
os
import
os
import
sys
import
signal
import
signal
import
threading
import
threading
import
asyncore
import
asyncore
...
@@ -62,7 +63,7 @@ import win32event
...
@@ -62,7 +63,7 @@ import win32event
import
ntsecuritycon
import
ntsecuritycon
import
logging
import
logging
logger
=
logging
.
getLogger
(
"WinSignalHandler"
)
logger
=
logging
.
getLogger
(
"WinSignalHandler"
)
# We simulate signals via win32 named events. This is the event name
# We simulate signals via win32 named events. This is the event name
# prefix we use - the "signal number" is appended to this name.
# prefix we use - the "signal number" is appended to this name.
...
@@ -76,15 +77,16 @@ winver = sys.getwindowsversion()
...
@@ -76,15 +77,16 @@ winver = sys.getwindowsversion()
if
winver
[
0
]
>=
5
and
winver
[
3
]
==
2
:
if
winver
[
0
]
>=
5
and
winver
[
3
]
==
2
:
event_name_prefix
=
"Global
\
\
"
+
event_name_prefix
event_name_prefix
=
"Global
\
\
"
+
event_name_prefix
def
createEventSecurityObject
():
def
createEventSecurityObject
():
# Create a security object giving World read/write access,
# Create a security object giving World read/write access,
# but only "Owner" modify access.
# but only "Owner" modify access.
sa
=
pywintypes
.
SECURITY_ATTRIBUTES
()
sa
=
pywintypes
.
SECURITY_ATTRIBUTES
()
sidEveryone
=
pywintypes
.
SID
()
sidEveryone
=
pywintypes
.
SID
()
sidEveryone
.
Initialize
(
ntsecuritycon
.
SECURITY_WORLD_SID_AUTHORITY
,
1
)
sidEveryone
.
Initialize
(
ntsecuritycon
.
SECURITY_WORLD_SID_AUTHORITY
,
1
)
sidEveryone
.
SetSubAuthority
(
0
,
ntsecuritycon
.
SECURITY_WORLD_RID
)
sidEveryone
.
SetSubAuthority
(
0
,
ntsecuritycon
.
SECURITY_WORLD_RID
)
sidCreator
=
pywintypes
.
SID
()
sidCreator
=
pywintypes
.
SID
()
sidCreator
.
Initialize
(
ntsecuritycon
.
SECURITY_CREATOR_SID_AUTHORITY
,
1
)
sidCreator
.
Initialize
(
ntsecuritycon
.
SECURITY_CREATOR_SID_AUTHORITY
,
1
)
sidCreator
.
SetSubAuthority
(
0
,
ntsecuritycon
.
SECURITY_CREATOR_OWNER_RID
)
sidCreator
.
SetSubAuthority
(
0
,
ntsecuritycon
.
SECURITY_CREATOR_OWNER_RID
)
acl
=
pywintypes
.
ACL
()
acl
=
pywintypes
.
ACL
()
...
@@ -94,9 +96,10 @@ def createEventSecurityObject():
...
@@ -94,9 +96,10 @@ def createEventSecurityObject():
sa
.
SetSecurityDescriptorDacl
(
1
,
acl
,
0
)
sa
.
SetSecurityDescriptorDacl
(
1
,
acl
,
0
)
return
sa
return
sa
def
wakeSelect
():
def
wakeSelect
():
"""Interrupt a sleeping asyncore 'select' call"""
"""Interrupt a sleeping asyncore 'select' call"""
# What is the right thing to do here?
# What is the right thing to do here?
# asyncore.close_all() works, but I fear that would
# asyncore.close_all() works, but I fear that would
# prevent the poll based graceful cleanup code from working.
# prevent the poll based graceful cleanup code from working.
# This seems to work :)
# This seems to work :)
...
@@ -104,7 +107,8 @@ def wakeSelect():
...
@@ -104,7 +107,8 @@ def wakeSelect():
if
hasattr
(
obj
,
"pull_trigger"
):
if
hasattr
(
obj
,
"pull_trigger"
):
obj
.
pull_trigger
()
obj
.
pull_trigger
()
class
SignalHandler
:
class
SignalHandler
(
object
):
def
__init__
(
self
):
def
__init__
(
self
):
self
.
registry
=
{}
self
.
registry
=
{}
...
@@ -113,7 +117,7 @@ class SignalHandler:
...
@@ -113,7 +117,7 @@ class SignalHandler:
self
.
shutdown_requested
=
False
self
.
shutdown_requested
=
False
# Register a "console control handler" for Ctrl+C/Break notification.
# Register a "console control handler" for Ctrl+C/Break notification.
SetConsoleCtrlHandler
(
consoleCtrlHandler
)
SetConsoleCtrlHandler
(
consoleCtrlHandler
)
# Start the thread that is watching for events.
# Start the thread that is watching for events.
thread
=
threading
.
Thread
(
target
=
self
.
signalCheckerThread
)
thread
=
threading
.
Thread
(
target
=
self
.
signalCheckerThread
)
# If something goes terribly wrong, don't wait for this thread!
# If something goes terribly wrong, don't wait for this thread!
...
@@ -126,12 +130,7 @@ class SignalHandler:
...
@@ -126,12 +130,7 @@ class SignalHandler:
logger
.
debug
(
"signal handler shutdown starting."
)
logger
.
debug
(
"signal handler shutdown starting."
)
self
.
shutdown_requested
=
1
self
.
shutdown_requested
=
1
win32event
.
SetEvent
(
self
.
admin_event_handle
)
win32event
.
SetEvent
(
self
.
admin_event_handle
)
# sadly, this can deadlock at shutdown when Ctrl+C is used
self
.
signal_thread
.
join
(
5
)
# should never block for long!
# (although not then the event is used to trigger shutdown)
# at least in build 204. Further updates as they come to hand...
# Remove the Windows control handler
#SetConsoleCtrlHandler(consoleCtrlHandler, 0)
self
.
signal_thread
.
join
(
5
)
# should never block for long!
self
.
registry
=
None
self
.
registry
=
None
self
.
event_handles
=
None
self
.
event_handles
=
None
...
@@ -139,7 +138,7 @@ class SignalHandler:
...
@@ -139,7 +138,7 @@ class SignalHandler:
logger
.
debug
(
"signal handler shutdown complete."
)
logger
.
debug
(
"signal handler shutdown complete."
)
def
consoleCtrlHandler
(
self
,
ctrlType
):
def
consoleCtrlHandler
(
self
,
ctrlType
):
"""Called by Windows on a new thread whenever a console control
"""Called by Windows on a new thread whenever a console control
event is raised."""
event is raised."""
logger
.
debug
(
"Windows control event %d"
%
ctrlType
)
logger
.
debug
(
"Windows control event %d"
%
ctrlType
)
sig
=
None
sig
=
None
...
@@ -153,13 +152,13 @@ class SignalHandler:
...
@@ -153,13 +152,13 @@ class SignalHandler:
# CTRL_CLOSE_EVENT gives us 5 seconds before displaying
# CTRL_CLOSE_EVENT gives us 5 seconds before displaying
# the "End process" dialog - so treat as 'fast'
# the "End process" dialog - so treat as 'fast'
sig
=
signal
.
SIGTERM
sig
=
signal
.
SIGTERM
elif
ctrlType
in
(
win32con
.
CTRL_LOGOFF_EVENT
,
elif
ctrlType
in
(
win32con
.
CTRL_LOGOFF_EVENT
,
win32con
.
CTRL_SHUTDOWN_EVENT
):
win32con
.
CTRL_SHUTDOWN_EVENT
):
# MSDN says:
# MSDN says:
# "Note that this signal is received only by services.
# "Note that this signal is received only by services.
# Interactive applications are terminated at logoff, so
# Interactive applications are terminated at logoff, so
# they are not present when the system sends this signal."
# they are not present when the system sends this signal."
# We can therefore ignore it (our service framework
# We can therefore ignore it (our service framework
# manages shutdown in this case)
# manages shutdown in this case)
pass
pass
else
:
else
:
...
@@ -169,9 +168,9 @@ class SignalHandler:
...
@@ -169,9 +168,9 @@ class SignalHandler:
# that we don't wake the select loop until after the shutdown
# that we don't wake the select loop until after the shutdown
# flags have been set.
# flags have been set.
result
=
0
result
=
0
if
sig
is
not
None
and
s
elf
.
registry
.
has_key
(
sig
)
:
if
sig
is
not
None
and
s
ig
in
self
.
registry
:
self
.
signalHandler
(
sig
,
None
)
self
.
signalHandler
(
sig
,
None
)
result
=
1
# don't call other handlers.
result
=
1
# don't call other handlers.
return
result
return
result
def
signalCheckerThread
(
self
):
def
signalCheckerThread
(
self
):
...
@@ -210,7 +209,8 @@ class SignalHandler:
...
@@ -210,7 +209,8 @@ class SignalHandler:
# Let the worker thread know there is a new handle.
# Let the worker thread know there is a new handle.
win32event
.
SetEvent
(
self
.
admin_event_handle
)
win32event
.
SetEvent
(
self
.
admin_event_handle
)
signame
=
get_signal_name
(
signum
)
signame
=
get_signal_name
(
signum
)
logger
.
debug
(
"Installed sighandler for %s (%s)"
%
(
signame
,
event_name
))
logger
.
debug
(
"Installed sighandler for %s (%s)"
%
(
signame
,
event_name
))
items
.
insert
(
0
,
handler
)
items
.
insert
(
0
,
handler
)
def
getRegisteredSignals
(
self
):
def
getRegisteredSignals
(
self
):
...
@@ -226,20 +226,23 @@ class SignalHandler:
...
@@ -226,20 +226,23 @@ class SignalHandler:
for
handler
in
self
.
registry
.
get
(
signum
,
[]):
for
handler
in
self
.
registry
.
get
(
signum
,
[]):
# Never let a bad handler prevent the standard signal
# Never let a bad handler prevent the standard signal
# handlers from running.
# handlers from running.
try
:
handler
()
try
:
except
SystemExit
,
rc
:
handler
()
# On Unix, signals are delivered to the main thread, so a
except
SystemExit
as
rc
:
# On Unix, signals are delivered to the main thread, so a
# SystemExit does the right thing. On Windows, we are on
# SystemExit does the right thing. On Windows, we are on
# our own thread, so throwing SystemExit there isn't a great
# our own thread, so throwing SystemExit there isn't a great
# idea. Just shutdown the main loop.
# idea. Just shutdown the main loop.
logger
.
debug
(
"Trapped SystemExit(%s) - doing Lifetime shutdown"
%
(
rc
,))
logger
.
debug
(
"Trapped SystemExit(%s) - doing Lifetime shutdown"
%
rc
)
Lifetime
.
shutdown
(
rc
)
Lifetime
.
shutdown
(
rc
)
except
:
except
:
logger
.
exception
(
"A handler for %s failed!'"
%
signame
)
logger
.
exception
(
"A handler for %s failed!'"
%
signame
)
wakeSelect
()
# trigger a walk around the Lifetime loop.
wakeSelect
()
# trigger a walk around the Lifetime loop.
_signals
=
None
_signals
=
None
def
get_signal_name
(
n
):
def
get_signal_name
(
n
):
"""Return the symbolic name for signal n.
"""Return the symbolic name for signal n.
...
@@ -257,19 +260,20 @@ def get_signal_name(n):
...
@@ -257,19 +260,20 @@ def get_signal_name(n):
_signals
[
v
]
=
k
_signals
[
v
]
=
k
# extra ones that aren't (weren't?) in Windows.
# extra ones that aren't (weren't?) in Windows.
for
name
,
val
in
(
"SIGHUP"
,
1
),
(
"SIGUSR1"
,
10
),
(
"SIGUSR2"
,
12
):
for
name
,
val
in
(
"SIGHUP"
,
1
),
(
"SIGUSR1"
,
10
),
(
"SIGUSR2"
,
12
):
if
n
ot
_signals
.
has_key
(
name
)
:
if
n
ame
not
in
_signals
:
_signals
[
val
]
=
name
_signals
[
val
]
=
name
return
_signals
.
get
(
n
,
'signal %d'
%
n
)
return
_signals
.
get
(
n
,
'signal %d'
%
n
)
# The win32 ConsoleCtrlHandler
def
consoleCtrlHandler
(
ctrlType
):
def
consoleCtrlHandler
(
ctrlType
):
# The win32 ConsoleCtrlHandler
return
SignalHandler
.
consoleCtrlHandler
(
ctrlType
)
return
SignalHandler
.
consoleCtrlHandler
(
ctrlType
)
# The SignalHandler is actually a singleton.
# The SignalHandler is actually a singleton.
SignalHandler
=
SignalHandler
()
SignalHandler
=
SignalHandler
()
# Need to be careful at shutdown - the 'signal watcher' thread which triggers
# Need to be careful at shutdown - the 'signal watcher' thread which triggers
# the shutdown may still be running when the main thread terminates and
# the shutdown may still be running when the main thread terminates and
# Python starts cleaning up.
# Python starts cleaning up.
atexit
.
register
(
SignalHandler
.
shutdown
)
atexit
.
register
(
SignalHandler
.
shutdown
)
src/Signals/__init__.py
View file @
966f7dfa
"""
Signals package __init__.py
"""
src/Signals/threads.py
View file @
966f7dfa
...
@@ -26,10 +26,10 @@ def dump_threads():
...
@@ -26,10 +26,10 @@ def dump_threads():
request
=
f
.
f_locals
.
get
(
'request'
)
request
=
f
.
f_locals
.
get
(
'request'
)
if
request
is
not
None
:
if
request
is
not
None
:
reqinfo
+=
(
request
.
get
(
'REQUEST_METHOD'
,
''
)
+
' '
+
reqinfo
+=
(
request
.
get
(
'REQUEST_METHOD'
,
''
)
+
' '
+
request
.
get
(
'PATH_INFO'
,
''
))
request
.
get
(
'PATH_INFO'
,
''
))
qs
=
request
.
get
(
'QUERY_STRING'
)
qs
=
request
.
get
(
'QUERY_STRING'
)
if
qs
:
if
qs
:
reqinfo
+=
'?'
+
qs
reqinfo
+=
'?'
+
qs
break
break
f
=
f
.
f_back
f
=
f
.
f_back
if
reqinfo
:
if
reqinfo
:
...
@@ -37,8 +37,8 @@ def dump_threads():
...
@@ -37,8 +37,8 @@ def dump_threads():
output
=
StringIO
()
output
=
StringIO
()
traceback
.
print_stack
(
frame
,
file
=
output
)
traceback
.
print_stack
(
frame
,
file
=
output
)
res
.
append
(
"Thread %s%s:
\
n
%s"
%
res
.
append
(
(
thread_id
,
reqinfo
,
output
.
getvalue
()))
"Thread %s%s:
\
n
%s"
%
(
thread_id
,
reqinfo
,
output
.
getvalue
()))
frames
=
None
frames
=
None
res
.
append
(
"End of dump"
)
res
.
append
(
"End of dump"
)
...
...
src/Zope2/Startup/__init__.py
View file @
966f7dfa
...
@@ -45,7 +45,7 @@ def get_starter():
...
@@ -45,7 +45,7 @@ def get_starter():
return
UnixZopeStarter
()
return
UnixZopeStarter
()
class
ZopeStarter
:
class
ZopeStarter
(
object
)
:
"""This is a class which starts a Zope server.
"""This is a class which starts a Zope server.
Making it a class makes it easier to test.
Making it a class makes it easier to test.
...
@@ -72,7 +72,6 @@ class ZopeStarter:
...
@@ -72,7 +72,6 @@ class ZopeStarter:
def
setConfiguration
(
self
,
cfg
):
def
setConfiguration
(
self
,
cfg
):
self
.
cfg
=
cfg
self
.
cfg
=
cfg
def
sendEvents
(
self
):
def
sendEvents
(
self
):
notify
(
ProcessStarting
())
notify
(
ProcessStarting
())
...
@@ -174,16 +173,14 @@ class ZopeStarter:
...
@@ -174,16 +173,14 @@ class ZopeStarter:
'The locale module could not be imported.
\
n
'
'The locale module could not be imported.
\
n
'
'To use localization options, you must ensure
\
n
'
'To use localization options, you must ensure
\
n
'
'that the locale module is compiled into your
\
n
'
'that the locale module is compiled into your
\
n
'
'Python installation.'
'Python installation.'
)
)
try
:
try
:
locale
.
setlocale
(
locale
.
LC_ALL
,
locale_id
)
locale
.
setlocale
(
locale
.
LC_ALL
,
locale_id
)
except
:
except
:
raise
ZConfig
.
ConfigurationError
(
raise
ZConfig
.
ConfigurationError
(
'The specified locale "%s" is not supported by your'
'The specified locale "%s" is not supported by your'
'system.
\
n
See your operating system documentation for '
'system.
\
n
See your operating system documentation for '
'more
\
n
information on locale support.'
%
locale_id
'more
\
n
information on locale support.'
%
locale_id
)
)
def
setupZServer
(
self
):
def
setupZServer
(
self
):
# Increase the number of threads
# Increase the number of threads
...
@@ -197,7 +194,8 @@ class ZopeStarter:
...
@@ -197,7 +194,8 @@ class ZopeStarter:
# This one has the delayed listening feature
# This one has the delayed listening feature
if
not
server
.
fast_listen
:
if
not
server
.
fast_listen
:
server
.
fast_listen
=
True
server
.
fast_listen
=
True
server
.
listen
(
1024
)
# same value as defined in medusa.http_server.py
# same value as defined in medusa.http_server.py
server
.
listen
(
1024
)
def
setupServers
(
self
):
def
setupServers
(
self
):
socket_err
=
(
socket_err
=
(
...
@@ -205,17 +203,16 @@ class ZopeStarter:
...
@@ -205,17 +203,16 @@ class ZopeStarter:
'This may mean that your user does not have permission to '
'This may mean that your user does not have permission to '
'bind to the port which the server is trying to use or the '
'bind to the port which the server is trying to use or the '
'port may already be in use by another application. '
'port may already be in use by another application. '
'(%s)'
'(%s)'
)
)
servers
=
[]
servers
=
[]
for
server
in
self
.
cfg
.
servers
:
for
server
in
self
.
cfg
.
servers
:
# create the server from the server factory
# create the server from the server factory
# set up in the config
# set up in the config
try
:
try
:
servers
.
append
(
server
.
create
())
servers
.
append
(
server
.
create
())
except
socket
.
error
,
e
:
except
socket
.
error
as
e
:
raise
ZConfig
.
ConfigurationError
(
socket_err
raise
ZConfig
.
ConfigurationError
(
%
(
server
.
servertype
(),
e
[
1
]))
socket_err
%
(
server
.
servertype
(),
e
[
1
]))
self
.
cfg
.
servers
=
servers
self
.
cfg
.
servers
=
servers
def
dropPrivileges
(
self
):
def
dropPrivileges
(
self
):
...
@@ -372,7 +369,7 @@ def dropPrivileges(cfg):
...
@@ -372,7 +369,7 @@ def dropPrivileges(cfg):
import
pwd
import
pwd
effective_user
=
cfg
.
effective_user
effective_user
=
cfg
.
effective_user
if
effective_user
is
None
:
if
effective_user
is
None
:
msg
=
(
'A user was not specified to setuid to; fix this to '
msg
=
(
'A user was not specified to setuid to; fix this to '
'start as root (change the effective-user directive '
'start as root (change the effective-user directive '
...
@@ -413,15 +410,15 @@ def dropPrivileges(cfg):
...
@@ -413,15 +410,15 @@ def dropPrivileges(cfg):
os
.
setuid
(
uid
)
os
.
setuid
(
uid
)
logger
.
info
(
'Set effective user to "%s"'
%
effective_user
)
logger
.
info
(
'Set effective user to "%s"'
%
effective_user
)
return
1
# for unit testing purposes
return
1
# for unit testing purposes
# DM 2004-11-24: added
def
_name2Ips
(
host
,
isIp_
=
compile
(
r'(\
d+
\.){3}'
).
match
):
def
_name2Ips
(
host
,
isIp_
=
compile
(
r'(\
d+
\.){3}'
).
match
):
'''map a name *host* to the sequence of its ip addresses;
'''map a name *host* to the sequence of its ip addresses;
use *host* itself (as sequence) if it already is an ip address.
use *host* itself (as sequence) if it already is an ip address.
Thus, if only a specific interface on a host is trusted,
Thus, if only a specific interface on a host is trusted,
identify it by its ip (and not the host name).
identify it by its ip (and not the host name).
'''
'''
if
isIp_
(
host
):
return
[
host
]
if
isIp_
(
host
):
return
[
host
]
return
gethostbyaddr
(
host
)[
2
]
return
gethostbyaddr
(
host
)[
2
]
src/Zope2/Startup/tests/testStarter.py
View file @
966f7dfa
...
@@ -34,6 +34,7 @@ from App.config import getConfiguration, setConfiguration
...
@@ -34,6 +34,7 @@ from App.config import getConfiguration, setConfiguration
TEMPNAME
=
tempfile
.
mktemp
()
TEMPNAME
=
tempfile
.
mktemp
()
TEMPPRODUCTS
=
os
.
path
.
join
(
TEMPNAME
,
"Products"
)
TEMPPRODUCTS
=
os
.
path
.
join
(
TEMPNAME
,
"Products"
)
def
getSchema
():
def
getSchema
():
startup
=
os
.
path
.
dirname
(
Zope2
.
Startup
.
__file__
)
startup
=
os
.
path
.
dirname
(
Zope2
.
Startup
.
__file__
)
schemafile
=
os
.
path
.
join
(
startup
,
'zopeschema.xml'
)
schemafile
=
os
.
path
.
join
(
startup
,
'zopeschema.xml'
)
...
@@ -45,10 +46,11 @@ def getSchema():
...
@@ -45,10 +46,11 @@ def getSchema():
logger_states
=
{}
logger_states
=
{}
for
name
in
(
None
,
'trace'
,
'access'
):
for
name
in
(
None
,
'trace'
,
'access'
):
logger
=
logging
.
getLogger
(
name
)
logger
=
logging
.
getLogger
(
name
)
logger_states
[
name
]
=
{
'level'
:
logger
.
level
,
logger_states
[
name
]
=
{
'level'
:
logger
.
level
,
'propagate'
:
logger
.
propagate
,
'propagate'
:
logger
.
propagate
,
'handlers'
:
logger
.
handlers
,
'handlers'
:
logger
.
handlers
,
'filters'
:
logger
.
filters
}
'filters'
:
logger
.
filters
}
class
ZopeStarterTestCase
(
LoggingTestHelper
,
unittest
.
TestCase
):
class
ZopeStarterTestCase
(
LoggingTestHelper
,
unittest
.
TestCase
):
...
@@ -94,7 +96,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -94,7 +96,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
try
:
try
:
os
.
mkdir
(
TEMPNAME
)
os
.
mkdir
(
TEMPNAME
)
os
.
mkdir
(
TEMPPRODUCTS
)
os
.
mkdir
(
TEMPPRODUCTS
)
except
OSError
,
why
:
except
OSError
as
why
:
if
why
==
17
:
if
why
==
17
:
# already exists
# already exists
pass
pass
...
@@ -110,10 +112,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -110,10 +112,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
conf
=
self
.
load_config_text
(
"""
conf
=
self
.
load_config_text
(
"""
instancehome <<INSTANCE_HOME>>
instancehome <<INSTANCE_HOME>>
locale en_GB"""
)
locale en_GB"""
)
except
ZConfig
.
DataConversionError
,
e
:
except
ZConfig
.
DataConversionError
as
e
:
# Skip this test if we don't have support.
# Skip this test if we don't have support.
if
e
.
message
.
startswith
(
if
e
.
message
.
startswith
(
'The specified locale "en_GB" is not supported'
):
'The specified locale "en_GB" is not supported'
):
return
return
raise
raise
starter
=
self
.
get_starter
(
conf
)
starter
=
self
.
get_starter
(
conf
)
...
@@ -146,16 +148,12 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -146,16 +148,12 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
# startup handler should take on the level of the event log handler
# startup handler should take on the level of the event log handler
# with the lowest level
# with the lowest level
logger
=
starter
.
event_logger
logger
=
starter
.
event_logger
self
.
assertEqual
(
starter
.
startup_handler
.
level
,
15
)
# 15 is BLATHER
self
.
assertEqual
(
starter
.
startup_handler
.
level
,
15
)
# 15 is BLATHER
self
.
assert_
(
starter
.
startup_handler
in
logger
.
handlers
)
self
.
assert_
(
starter
.
startup_handler
in
logger
.
handlers
)
self
.
assertEqual
(
logger
.
level
,
15
)
self
.
assertEqual
(
logger
.
level
,
15
)
# We expect a debug handler and the startup handler:
# We expect a debug handler and the startup handler:
self
.
assertEqual
(
len
(
logger
.
handlers
),
2
)
self
.
assertEqual
(
len
(
logger
.
handlers
),
2
)
# XXX need to check that log messages get written to
# sys.stderr, not that the stream identity for the startup
# handler matches
#self.assertEqual(starter.startup_handler.stream, sys.stderr)
conf
=
self
.
load_config_text
(
"""
conf
=
self
.
load_config_text
(
"""
instancehome <<INSTANCE_HOME>>
instancehome <<INSTANCE_HOME>>
debug-mode off
debug-mode off
...
@@ -168,10 +166,6 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -168,10 +166,6 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
</eventlog>"""
)
</eventlog>"""
)
starter
=
self
.
get_starter
(
conf
)
starter
=
self
.
get_starter
(
conf
)
starter
.
setupInitialLogging
()
starter
.
setupInitialLogging
()
# XXX need to check that log messages get written to
# sys.stderr, not that the stream identity for the startup
# handler matches
#self.assertNotEqual(starter.startup_handler.stream, sys.stderr)
def
testSetupZServerThreads
(
self
):
def
testSetupZServerThreads
(
self
):
conf
=
self
.
load_config_text
(
"""
conf
=
self
.
load_config_text
(
"""
...
@@ -193,7 +187,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -193,7 +187,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
</http-server>
</http-server>
<ftp-server>
<ftp-server>
address %(ftp)s
address %(ftp)s
</ftp-server>"""
%
dict
(
http
=
port
,
ftp
=
port
+
1
)
</ftp-server>"""
%
dict
(
http
=
port
,
ftp
=
port
+
1
)
)
)
starter
=
self
.
get_starter
(
conf
)
starter
=
self
.
get_starter
(
conf
)
# do the job the 'handler' would have done (call prepare)
# do the job the 'handler' would have done (call prepare)
...
@@ -207,7 +201,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -207,7 +201,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
self
.
assertEqual
(
conf
.
servers
[
1
].
__class__
,
self
.
assertEqual
(
conf
.
servers
[
1
].
__class__
,
ZServer
.
FTPServer
)
ZServer
.
FTPServer
)
finally
:
finally
:
del
conf
.
servers
# should release servers
del
conf
.
servers
# should release servers
pass
pass
def
testDropPrivileges
(
self
):
def
testDropPrivileges
(
self
):
...
@@ -216,8 +210,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -216,8 +210,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
if
os
.
name
!=
'posix'
:
if
os
.
name
!=
'posix'
:
return
return
_old_getuid
=
os
.
getuid
_old_getuid
=
os
.
getuid
def
_return0
():
def
_return0
():
return
0
return
0
def
make_starter
(
conf
):
def
make_starter
(
conf
):
# remove the debug handler, since we don't want junk on
# remove the debug handler, since we don't want junk on
# stderr for the tests
# stderr for the tests
...
@@ -292,8 +288,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -292,8 +288,10 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
self
.
assertEqual
(
logger
.
level
,
logging
.
INFO
)
self
.
assertEqual
(
logger
.
level
,
logging
.
INFO
)
l
=
open
(
os
.
path
.
join
(
TEMPNAME
,
'event.log'
)).
read
()
l
=
open
(
os
.
path
.
join
(
TEMPNAME
,
'event.log'
)).
read
()
self
.
assertTrue
(
l
.
find
(
'hello'
)
>
-
1
)
self
.
assertTrue
(
l
.
find
(
'hello'
)
>
-
1
)
self
.
assertTrue
(
os
.
path
.
exists
(
os
.
path
.
join
(
TEMPNAME
,
'Z2.log'
)))
self
.
assertTrue
(
self
.
assertTrue
(
os
.
path
.
exists
(
os
.
path
.
join
(
TEMPNAME
,
'trace.log'
)))
os
.
path
.
exists
(
os
.
path
.
join
(
TEMPNAME
,
'Z2.log'
)))
self
.
assertTrue
(
os
.
path
.
exists
(
os
.
path
.
join
(
TEMPNAME
,
'trace.log'
)))
finally
:
finally
:
for
name
in
(
'event.log'
,
'Z2.log'
,
'trace.log'
):
for
name
in
(
'event.log'
,
'Z2.log'
,
'trace.log'
):
try
:
try
:
...
@@ -355,12 +353,11 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -355,12 +353,11 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
conf
=
self
.
load_config_text
(
"""
conf
=
self
.
load_config_text
(
"""
instancehome <<INSTANCE_HOME>>
instancehome <<INSTANCE_HOME>>
python-check-interval %d
python-check-interval %d
"""
%
newcheckinterval
"""
%
newcheckinterval
)
)
try
:
try
:
starter
=
self
.
get_starter
(
conf
)
starter
=
self
.
get_starter
(
conf
)
starter
.
setupInterpreter
()
starter
.
setupInterpreter
()
self
.
assertEqual
(
sys
.
getcheckinterval
()
,
newcheckinterval
)
self
.
assertEqual
(
sys
.
getcheckinterval
(),
newcheckinterval
)
finally
:
finally
:
sys
.
setcheckinterval
(
oldcheckinterval
)
sys
.
setcheckinterval
(
oldcheckinterval
)
...
@@ -369,7 +366,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -369,7 +366,7 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
try
:
try
:
os
.
mkdir
(
TEMPNAME
)
os
.
mkdir
(
TEMPNAME
)
os
.
mkdir
(
TEMPPRODUCTS
)
os
.
mkdir
(
TEMPPRODUCTS
)
except
OSError
,
why
:
except
OSError
as
why
:
if
why
==
errno
.
EEXIST
:
if
why
==
errno
.
EEXIST
:
# already exists
# already exists
pass
pass
...
@@ -392,7 +389,3 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
...
@@ -392,7 +389,3 @@ class ZopeStarterTestCase(LoggingTestHelper, unittest.TestCase):
except
:
except
:
pass
pass
setConfiguration
(
old_config
)
setConfiguration
(
old_config
)
def
test_suite
():
return
unittest
.
makeSuite
(
ZopeStarterTestCase
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment