We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Gunicorn --reload option reloads indefinitely
Running any application, such as the following application (from gunicorn.org) with the `--reload` option and then making a trivial change leads to a never-ending reload cycle on my system.

```
def app(environ, start_response):
      data = "Hello, World!\n"
      start_response("200 OK", [
          ("Content-Type", "text/plain"),
          ("Content-Length", str(len(data)))
      ])
      return iter([data])
```

```
$ gunicorn --version
gunicorn (version 19.3.0)
$ python --version
Python 3.4.3
$ gunicorn --reload app:app -b localhost:8000
[2015-10-16 13:01:58 +0200] [42184] [INFO] Starting gunicorn 19.3.0
[2015-10-16 13:01:58 +0200] [42184] [INFO] Listening at: http://127.0.0.1:8000 (42184)
[2015-10-16 13:01:58 +0200] [42184] [INFO] Using worker: sync
[2015-10-16 13:01:58 +0200] [42187] [INFO] Booting worker with pid: 42187
[2015-10-16 13:02:05 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:06 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:07 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:08 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:09 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:10 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:11 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:12 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
[2015-10-16 13:02:13 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified
^C[2015-10-16 13:02:13 +0200] [42184] [INFO] Handling signal: int
[2015-10-16 13:02:13 +0200] [42187] [INFO] Worker exiting (pid: 42187)
[2015-10-16 13:02:13 +0200] [42184] [INFO] Shutting down: Master
```

Please let me know what other debug information I can provide.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gunicorn/workers/base.py`
Content:
```
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 
6 from datetime import datetime
7 import os
8 from random import randint
9 import signal
10 from ssl import SSLError
11 import sys
12 import time
13 import traceback
14 
15 from gunicorn import util
16 from gunicorn.workers.workertmp import WorkerTmp
17 from gunicorn.reloader import Reloader
18 from gunicorn.http.errors import (
19     InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,
20     InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,
21 )
22 from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
23 from gunicorn.http.wsgi import default_environ, Response
24 from gunicorn.six import MAXSIZE
25 
26 
27 class Worker(object):
28 
29     SIGNALS = [getattr(signal, "SIG%s" % x)
30             for x in "ABRT HUP QUIT INT TERM USR1 USR2 WINCH CHLD".split()]
31 
32     PIPE = []
33 
34     def __init__(self, age, ppid, sockets, app, timeout, cfg, log):
35         """\
36         This is called pre-fork so it shouldn't do anything to the
37         current process. If there's a need to make process wide
38         changes you'll want to do that in ``self.init_process()``.
39         """
40         self.age = age
41         self.ppid = ppid
42         self.sockets = sockets
43         self.app = app
44         self.timeout = timeout
45         self.cfg = cfg
46         self.booted = False
47         self.aborted = False
48         self.reloader = None
49 
50         self.nr = 0
51         jitter = randint(0, cfg.max_requests_jitter)
52         self.max_requests = cfg.max_requests + jitter or MAXSIZE
53         self.alive = True
54         self.log = log
55         self.tmp = WorkerTmp(cfg)
56 
57     def __str__(self):
58         return "<Worker %s>" % self.pid
59 
60     @property
61     def pid(self):
62         return os.getpid()
63 
64     def notify(self):
65         """\
66         Your worker subclass must arrange to have this method called
67         once every ``self.timeout`` seconds. If you fail in accomplishing
68         this task, the master process will murder your workers.
69         """
70         self.tmp.notify()
71 
72     def run(self):
73         """\
74         This is the mainloop of a worker process. You should override
75         this method in a subclass to provide the intended behaviour
76         for your particular evil schemes.
77         """
78         raise NotImplementedError()
79 
80     def init_process(self):
81         """\
82         If you override this method in a subclass, the last statement
83         in the function should be to call this method with
84         super(MyWorkerClass, self).init_process() so that the ``run()``
85         loop is initiated.
86         """
87 
88         # start the reloader
89         if self.cfg.reload:
90             def changed(fname):
91                 self.log.info("Worker reloading: %s modified", fname)
92                 os.kill(self.pid, signal.SIGQUIT)
93             self.reloader = Reloader(callback=changed)
94             self.reloader.start()
95 
96         # set environment' variables
97         if self.cfg.env:
98             for k, v in self.cfg.env.items():
99                 os.environ[k] = v
100 
101         util.set_owner_process(self.cfg.uid, self.cfg.gid)
102 
103         # Reseed the random number generator
104         util.seed()
105 
106         # For waking ourselves up
107         self.PIPE = os.pipe()
108         for p in self.PIPE:
109             util.set_non_blocking(p)
110             util.close_on_exec(p)
111 
112         # Prevent fd inheritance
113         [util.close_on_exec(s) for s in self.sockets]
114         util.close_on_exec(self.tmp.fileno())
115 
116         self.wait_fds = self.sockets + [self.PIPE[0]]
117 
118         self.log.close_on_exec()
119 
120         self.init_signals()
121 
122         self.load_wsgi()
123 
124         self.cfg.post_worker_init(self)
125 
126         # Enter main run loop
127         self.booted = True
128         self.run()
129 
130     def load_wsgi(self):
131         try:
132             self.wsgi = self.app.wsgi()
133         except SyntaxError as e:
134             if not self.cfg.reload:
135                 raise
136 
137             self.log.exception(e)
138 
139             # fix from PR #1228
140             # storing the traceback into exc_tb will create a circular reference.
141             # per https://docs.python.org/2/library/sys.html#sys.exc_info warning,
142             # delete the traceback after use.
143             try:
144                 exc_type, exc_val, exc_tb = sys.exc_info()
145                 self.reloader.add_extra_file(exc_val.filename)
146 
147                 tb_string = traceback.format_tb(exc_tb)
148                 self.wsgi = util.make_fail_app(tb_string)
149             finally:
150                 del exc_tb
151 
152     def init_signals(self):
153         # reset signaling
154         [signal.signal(s, signal.SIG_DFL) for s in self.SIGNALS]
155         # init new signaling
156         signal.signal(signal.SIGQUIT, self.handle_quit)
157         signal.signal(signal.SIGTERM, self.handle_exit)
158         signal.signal(signal.SIGINT, self.handle_quit)
159         signal.signal(signal.SIGWINCH, self.handle_winch)
160         signal.signal(signal.SIGUSR1, self.handle_usr1)
161         signal.signal(signal.SIGABRT, self.handle_abort)
162 
163         # Don't let SIGTERM and SIGUSR1 disturb active requests
164         # by interrupting system calls
165         if hasattr(signal, 'siginterrupt'):  # python >= 2.6
166             signal.siginterrupt(signal.SIGTERM, False)
167             signal.siginterrupt(signal.SIGUSR1, False)
168 
169         if hasattr(signal, 'set_wakeup_fd'):
170             signal.set_wakeup_fd(self.PIPE[1])
171 
172     def handle_usr1(self, sig, frame):
173         self.log.reopen_files()
174 
175     def handle_exit(self, sig, frame):
176         self.alive = False
177 
178     def handle_quit(self, sig, frame):
179         self.alive = False
180         # worker_int callback
181         self.cfg.worker_int(self)
182         time.sleep(0.1)
183         sys.exit(0)
184 
185     def handle_abort(self, sig, frame):
186         self.alive = False
187         self.cfg.worker_abort(self)
188         sys.exit(1)
189 
190     def handle_error(self, req, client, addr, exc):
191         request_start = datetime.now()
192         addr = addr or ('', -1)  # unix socket case
193         if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod,
194                 InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,
195                 LimitRequestLine, LimitRequestHeaders,
196                 InvalidProxyLine, ForbiddenProxyRequest,
197                 SSLError)):
198 
199             status_int = 400
200             reason = "Bad Request"
201 
202             if isinstance(exc, InvalidRequestLine):
203                 mesg = "Invalid Request Line '%s'" % str(exc)
204             elif isinstance(exc, InvalidRequestMethod):
205                 mesg = "Invalid Method '%s'" % str(exc)
206             elif isinstance(exc, InvalidHTTPVersion):
207                 mesg = "Invalid HTTP Version '%s'" % str(exc)
208             elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)):
209                 mesg = "%s" % str(exc)
210                 if not req and hasattr(exc, "req"):
211                     req = exc.req  # for access log
212             elif isinstance(exc, LimitRequestLine):
213                 mesg = "%s" % str(exc)
214             elif isinstance(exc, LimitRequestHeaders):
215                 mesg = "Error parsing headers: '%s'" % str(exc)
216             elif isinstance(exc, InvalidProxyLine):
217                 mesg = "'%s'" % str(exc)
218             elif isinstance(exc, ForbiddenProxyRequest):
219                 reason = "Forbidden"
220                 mesg = "Request forbidden"
221                 status_int = 403
222             elif isinstance(exc, SSLError):
223                 reason = "Forbidden"
224                 mesg = "'%s'" % str(exc)
225                 status_int = 403
226 
227             msg = "Invalid request from ip={ip}: {error}"
228             self.log.debug(msg.format(ip=addr[0], error=str(exc)))
229         else:
230             if hasattr(req, "uri"):
231                 self.log.exception("Error handling request %s", req.uri)
232             status_int = 500
233             reason = "Internal Server Error"
234             mesg = ""
235 
236         if req is not None:
237             request_time = datetime.now() - request_start
238             environ = default_environ(req, client, self.cfg)
239             environ['REMOTE_ADDR'] = addr[0]
240             environ['REMOTE_PORT'] = str(addr[1])
241             resp = Response(req, client, self.cfg)
242             resp.status = "%s %s" % (status_int, reason)
243             resp.response_length = len(mesg)
244             self.log.access(resp, req, environ, request_time)
245 
246         try:
247             util.write_error(client, status_int, reason, mesg)
248         except:
249             self.log.debug("Failed to send error message.")
250 
251     def handle_winch(self, sig, fname):
252         # Ignore SIGWINCH in worker. Fixes a crash on OpenBSD.
253         return
254
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py
--- a/gunicorn/workers/base.py
+++ b/gunicorn/workers/base.py
@@ -89,7 +89,11 @@
         if self.cfg.reload:
             def changed(fname):
                 self.log.info("Worker reloading: %s modified", fname)
-                os.kill(self.pid, signal.SIGQUIT)
+                self.alive = False
+                self.cfg.worker_int(self)
+                time.sleep(0.1)
+                sys.exit(0)
+
             self.reloader = Reloader(callback=changed)
             self.reloader.start()

{"golden_diff": "diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py\n--- a/gunicorn/workers/base.py\n+++ b/gunicorn/workers/base.py\n@@ -89,7 +89,11 @@\n         if self.cfg.reload:\n             def changed(fname):\n                 self.log.info(\"Worker reloading: %s modified\", fname)\n-                os.kill(self.pid, signal.SIGQUIT)\n+                self.alive = False\n+                self.cfg.worker_int(self)\n+                time.sleep(0.1)\n+                sys.exit(0)\n+\n             self.reloader = Reloader(callback=changed)\n             self.reloader.start()\n", "issue": "Gunicorn --reload option reloads indefinitely\nRunning any application, such as the following application (from gunicorn.org) with the `--reload` option and then making a trivial change leads to a never-ending reload cycle on my system.\n\n```\ndef app(environ, start_response):\n      data = \"Hello, World!\\n\"\n      start_response(\"200 OK\", [\n          (\"Content-Type\", \"text/plain\"),\n          (\"Content-Length\", str(len(data)))\n      ])\n      return iter([data])\n```\n\n```\n$ gunicorn --version\ngunicorn (version 19.3.0)\n$ python --version\nPython 3.4.3\n$ gunicorn --reload app:app -b localhost:8000\n[2015-10-16 13:01:58 +0200] [42184] [INFO] Starting gunicorn 19.3.0\n[2015-10-16 13:01:58 +0200] [42184] [INFO] Listening at: http://127.0.0.1:8000 (42184)\n[2015-10-16 13:01:58 +0200] [42184] [INFO] Using worker: sync\n[2015-10-16 13:01:58 +0200] [42187] [INFO] Booting worker with pid: 42187\n[2015-10-16 13:02:05 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:06 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:07 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:08 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:09 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:10 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:11 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:12 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n[2015-10-16 13:02:13 +0200] [42187] [INFO] Worker reloading: /Users/lyschoening/app.py modified\n^C[2015-10-16 13:02:13 +0200] [42184] [INFO] Handling signal: int\n[2015-10-16 13:02:13 +0200] [42187] [INFO] Worker exiting (pid: 42187)\n[2015-10-16 13:02:13 +0200] [42184] [INFO] Shutting down: Master\n```\n\nPlease let me know what other debug information I can provide.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -\n#\n# This file is part of gunicorn released under the MIT license.\n# See the NOTICE for more information.\n\nfrom datetime import datetime\nimport os\nfrom random import randint\nimport signal\nfrom ssl import SSLError\nimport sys\nimport time\nimport traceback\n\nfrom gunicorn import util\nfrom gunicorn.workers.workertmp import WorkerTmp\nfrom gunicorn.reloader import Reloader\nfrom gunicorn.http.errors import (\n    InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,\n    InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,\n)\nfrom gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest\nfrom gunicorn.http.wsgi import default_environ, Response\nfrom gunicorn.six import MAXSIZE\n\n\nclass Worker(object):\n\n    SIGNALS = [getattr(signal, \"SIG%s\" % x)\n            for x in \"ABRT HUP QUIT INT TERM USR1 USR2 WINCH CHLD\".split()]\n\n    PIPE = []\n\n    def __init__(self, age, ppid, sockets, app, timeout, cfg, log):\n        \"\"\"\\\n        This is called pre-fork so it shouldn't do anything to the\n        current process. If there's a need to make process wide\n        changes you'll want to do that in ``self.init_process()``.\n        \"\"\"\n        self.age = age\n        self.ppid = ppid\n        self.sockets = sockets\n        self.app = app\n        self.timeout = timeout\n        self.cfg = cfg\n        self.booted = False\n        self.aborted = False\n        self.reloader = None\n\n        self.nr = 0\n        jitter = randint(0, cfg.max_requests_jitter)\n        self.max_requests = cfg.max_requests + jitter or MAXSIZE\n        self.alive = True\n        self.log = log\n        self.tmp = WorkerTmp(cfg)\n\n    def __str__(self):\n        return \"<Worker %s>\" % self.pid\n\n    @property\n    def pid(self):\n        return os.getpid()\n\n    def notify(self):\n        \"\"\"\\\n        Your worker subclass must arrange to have this method called\n        once every ``self.timeout`` seconds. If you fail in accomplishing\n        this task, the master process will murder your workers.\n        \"\"\"\n        self.tmp.notify()\n\n    def run(self):\n        \"\"\"\\\n        This is the mainloop of a worker process. You should override\n        this method in a subclass to provide the intended behaviour\n        for your particular evil schemes.\n        \"\"\"\n        raise NotImplementedError()\n\n    def init_process(self):\n        \"\"\"\\\n        If you override this method in a subclass, the last statement\n        in the function should be to call this method with\n        super(MyWorkerClass, self).init_process() so that the ``run()``\n        loop is initiated.\n        \"\"\"\n\n        # start the reloader\n        if self.cfg.reload:\n            def changed(fname):\n                self.log.info(\"Worker reloading: %s modified\", fname)\n                os.kill(self.pid, signal.SIGQUIT)\n            self.reloader = Reloader(callback=changed)\n            self.reloader.start()\n\n        # set environment' variables\n        if self.cfg.env:\n            for k, v in self.cfg.env.items():\n                os.environ[k] = v\n\n        util.set_owner_process(self.cfg.uid, self.cfg.gid)\n\n        # Reseed the random number generator\n        util.seed()\n\n        # For waking ourselves up\n        self.PIPE = os.pipe()\n        for p in self.PIPE:\n            util.set_non_blocking(p)\n            util.close_on_exec(p)\n\n        # Prevent fd inheritance\n        [util.close_on_exec(s) for s in self.sockets]\n        util.close_on_exec(self.tmp.fileno())\n\n        self.wait_fds = self.sockets + [self.PIPE[0]]\n\n        self.log.close_on_exec()\n\n        self.init_signals()\n\n        self.load_wsgi()\n\n        self.cfg.post_worker_init(self)\n\n        # Enter main run loop\n        self.booted = True\n        self.run()\n\n    def load_wsgi(self):\n        try:\n            self.wsgi = self.app.wsgi()\n        except SyntaxError as e:\n            if not self.cfg.reload:\n                raise\n\n            self.log.exception(e)\n\n            # fix from PR #1228\n            # storing the traceback into exc_tb will create a circular reference.\n            # per https://docs.python.org/2/library/sys.html#sys.exc_info warning,\n            # delete the traceback after use.\n            try:\n                exc_type, exc_val, exc_tb = sys.exc_info()\n                self.reloader.add_extra_file(exc_val.filename)\n\n                tb_string = traceback.format_tb(exc_tb)\n                self.wsgi = util.make_fail_app(tb_string)\n            finally:\n                del exc_tb\n\n    def init_signals(self):\n        # reset signaling\n        [signal.signal(s, signal.SIG_DFL) for s in self.SIGNALS]\n        # init new signaling\n        signal.signal(signal.SIGQUIT, self.handle_quit)\n        signal.signal(signal.SIGTERM, self.handle_exit)\n        signal.signal(signal.SIGINT, self.handle_quit)\n        signal.signal(signal.SIGWINCH, self.handle_winch)\n        signal.signal(signal.SIGUSR1, self.handle_usr1)\n        signal.signal(signal.SIGABRT, self.handle_abort)\n\n        # Don't let SIGTERM and SIGUSR1 disturb active requests\n        # by interrupting system calls\n        if hasattr(signal, 'siginterrupt'):  # python >= 2.6\n            signal.siginterrupt(signal.SIGTERM, False)\n            signal.siginterrupt(signal.SIGUSR1, False)\n\n        if hasattr(signal, 'set_wakeup_fd'):\n            signal.set_wakeup_fd(self.PIPE[1])\n\n    def handle_usr1(self, sig, frame):\n        self.log.reopen_files()\n\n    def handle_exit(self, sig, frame):\n        self.alive = False\n\n    def handle_quit(self, sig, frame):\n        self.alive = False\n        # worker_int callback\n        self.cfg.worker_int(self)\n        time.sleep(0.1)\n        sys.exit(0)\n\n    def handle_abort(self, sig, frame):\n        self.alive = False\n        self.cfg.worker_abort(self)\n        sys.exit(1)\n\n    def handle_error(self, req, client, addr, exc):\n        request_start = datetime.now()\n        addr = addr or ('', -1)  # unix socket case\n        if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod,\n                InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,\n                LimitRequestLine, LimitRequestHeaders,\n                InvalidProxyLine, ForbiddenProxyRequest,\n                SSLError)):\n\n            status_int = 400\n            reason = \"Bad Request\"\n\n            if isinstance(exc, InvalidRequestLine):\n                mesg = \"Invalid Request Line '%s'\" % str(exc)\n            elif isinstance(exc, InvalidRequestMethod):\n                mesg = \"Invalid Method '%s'\" % str(exc)\n            elif isinstance(exc, InvalidHTTPVersion):\n                mesg = \"Invalid HTTP Version '%s'\" % str(exc)\n            elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)):\n                mesg = \"%s\" % str(exc)\n                if not req and hasattr(exc, \"req\"):\n                    req = exc.req  # for access log\n            elif isinstance(exc, LimitRequestLine):\n                mesg = \"%s\" % str(exc)\n            elif isinstance(exc, LimitRequestHeaders):\n                mesg = \"Error parsing headers: '%s'\" % str(exc)\n            elif isinstance(exc, InvalidProxyLine):\n                mesg = \"'%s'\" % str(exc)\n            elif isinstance(exc, ForbiddenProxyRequest):\n                reason = \"Forbidden\"\n                mesg = \"Request forbidden\"\n                status_int = 403\n            elif isinstance(exc, SSLError):\n                reason = \"Forbidden\"\n                mesg = \"'%s'\" % str(exc)\n                status_int = 403\n\n            msg = \"Invalid request from ip={ip}: {error}\"\n            self.log.debug(msg.format(ip=addr[0], error=str(exc)))\n        else:\n            if hasattr(req, \"uri\"):\n                self.log.exception(\"Error handling request %s\", req.uri)\n            status_int = 500\n            reason = \"Internal Server Error\"\n            mesg = \"\"\n\n        if req is not None:\n            request_time = datetime.now() - request_start\n            environ = default_environ(req, client, self.cfg)\n            environ['REMOTE_ADDR'] = addr[0]\n            environ['REMOTE_PORT'] = str(addr[1])\n            resp = Response(req, client, self.cfg)\n            resp.status = \"%s %s\" % (status_int, reason)\n            resp.response_length = len(mesg)\n            self.log.access(resp, req, environ, request_time)\n\n        try:\n            util.write_error(client, status_int, reason, mesg)\n        except:\n            self.log.debug(\"Failed to send error message.\")\n\n    def handle_winch(self, sig, fname):\n        # Ignore SIGWINCH in worker. Fixes a crash on OpenBSD.\n        return\n", "path": "gunicorn/workers/base.py"}], "after_files": [{"content": "# -*- coding: utf-8 -\n#\n# This file is part of gunicorn released under the MIT license.\n# See the NOTICE for more information.\n\nfrom datetime import datetime\nimport os\nfrom random import randint\nimport signal\nfrom ssl import SSLError\nimport sys\nimport time\nimport traceback\n\nfrom gunicorn import util\nfrom gunicorn.workers.workertmp import WorkerTmp\nfrom gunicorn.reloader import Reloader\nfrom gunicorn.http.errors import (\n    InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,\n    InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,\n)\nfrom gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest\nfrom gunicorn.http.wsgi import default_environ, Response\nfrom gunicorn.six import MAXSIZE\n\n\nclass Worker(object):\n\n    SIGNALS = [getattr(signal, \"SIG%s\" % x)\n            for x in \"ABRT HUP QUIT INT TERM USR1 USR2 WINCH CHLD\".split()]\n\n    PIPE = []\n\n    def __init__(self, age, ppid, sockets, app, timeout, cfg, log):\n        \"\"\"\\\n        This is called pre-fork so it shouldn't do anything to the\n        current process. If there's a need to make process wide\n        changes you'll want to do that in ``self.init_process()``.\n        \"\"\"\n        self.age = age\n        self.ppid = ppid\n        self.sockets = sockets\n        self.app = app\n        self.timeout = timeout\n        self.cfg = cfg\n        self.booted = False\n        self.aborted = False\n        self.reloader = None\n\n        self.nr = 0\n        jitter = randint(0, cfg.max_requests_jitter)\n        self.max_requests = cfg.max_requests + jitter or MAXSIZE\n        self.alive = True\n        self.log = log\n        self.tmp = WorkerTmp(cfg)\n\n    def __str__(self):\n        return \"<Worker %s>\" % self.pid\n\n    @property\n    def pid(self):\n        return os.getpid()\n\n    def notify(self):\n        \"\"\"\\\n        Your worker subclass must arrange to have this method called\n        once every ``self.timeout`` seconds. If you fail in accomplishing\n        this task, the master process will murder your workers.\n        \"\"\"\n        self.tmp.notify()\n\n    def run(self):\n        \"\"\"\\\n        This is the mainloop of a worker process. You should override\n        this method in a subclass to provide the intended behaviour\n        for your particular evil schemes.\n        \"\"\"\n        raise NotImplementedError()\n\n    def init_process(self):\n        \"\"\"\\\n        If you override this method in a subclass, the last statement\n        in the function should be to call this method with\n        super(MyWorkerClass, self).init_process() so that the ``run()``\n        loop is initiated.\n        \"\"\"\n\n        # start the reloader\n        if self.cfg.reload:\n            def changed(fname):\n                self.log.info(\"Worker reloading: %s modified\", fname)\n                self.alive = False\n                self.cfg.worker_int(self)\n                time.sleep(0.1)\n                sys.exit(0)\n\n            self.reloader = Reloader(callback=changed)\n            self.reloader.start()\n\n        # set environment' variables\n        if self.cfg.env:\n            for k, v in self.cfg.env.items():\n                os.environ[k] = v\n\n        util.set_owner_process(self.cfg.uid, self.cfg.gid)\n\n        # Reseed the random number generator\n        util.seed()\n\n        # For waking ourselves up\n        self.PIPE = os.pipe()\n        for p in self.PIPE:\n            util.set_non_blocking(p)\n            util.close_on_exec(p)\n\n        # Prevent fd inheritance\n        [util.close_on_exec(s) for s in self.sockets]\n        util.close_on_exec(self.tmp.fileno())\n\n        self.wait_fds = self.sockets + [self.PIPE[0]]\n\n        self.log.close_on_exec()\n\n        self.init_signals()\n\n        self.load_wsgi()\n\n        self.cfg.post_worker_init(self)\n\n        # Enter main run loop\n        self.booted = True\n        self.run()\n\n    def load_wsgi(self):\n        try:\n            self.wsgi = self.app.wsgi()\n        except SyntaxError as e:\n            if not self.cfg.reload:\n                raise\n\n            self.log.exception(e)\n\n            # fix from PR #1228\n            # storing the traceback into exc_tb will create a circular reference.\n            # per https://docs.python.org/2/library/sys.html#sys.exc_info warning,\n            # delete the traceback after use.\n            try:\n                exc_type, exc_val, exc_tb = sys.exc_info()\n                self.reloader.add_extra_file(exc_val.filename)\n\n                tb_string = traceback.format_tb(exc_tb)\n                self.wsgi = util.make_fail_app(tb_string)\n            finally:\n                del exc_tb\n\n    def init_signals(self):\n        # reset signaling\n        [signal.signal(s, signal.SIG_DFL) for s in self.SIGNALS]\n        # init new signaling\n        signal.signal(signal.SIGQUIT, self.handle_quit)\n        signal.signal(signal.SIGTERM, self.handle_exit)\n        signal.signal(signal.SIGINT, self.handle_quit)\n        signal.signal(signal.SIGWINCH, self.handle_winch)\n        signal.signal(signal.SIGUSR1, self.handle_usr1)\n        signal.signal(signal.SIGABRT, self.handle_abort)\n\n        # Don't let SIGTERM and SIGUSR1 disturb active requests\n        # by interrupting system calls\n        if hasattr(signal, 'siginterrupt'):  # python >= 2.6\n            signal.siginterrupt(signal.SIGTERM, False)\n            signal.siginterrupt(signal.SIGUSR1, False)\n\n        if hasattr(signal, 'set_wakeup_fd'):\n            signal.set_wakeup_fd(self.PIPE[1])\n\n    def handle_usr1(self, sig, frame):\n        self.log.reopen_files()\n\n    def handle_exit(self, sig, frame):\n        self.alive = False\n\n    def handle_quit(self, sig, frame):\n        self.alive = False\n        # worker_int callback\n        self.cfg.worker_int(self)\n        time.sleep(0.1)\n        sys.exit(0)\n\n    def handle_abort(self, sig, frame):\n        self.alive = False\n        self.cfg.worker_abort(self)\n        sys.exit(1)\n\n    def handle_error(self, req, client, addr, exc):\n        request_start = datetime.now()\n        addr = addr or ('', -1)  # unix socket case\n        if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod,\n                InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,\n                LimitRequestLine, LimitRequestHeaders,\n                InvalidProxyLine, ForbiddenProxyRequest,\n                SSLError)):\n\n            status_int = 400\n            reason = \"Bad Request\"\n\n            if isinstance(exc, InvalidRequestLine):\n                mesg = \"Invalid Request Line '%s'\" % str(exc)\n            elif isinstance(exc, InvalidRequestMethod):\n                mesg = \"Invalid Method '%s'\" % str(exc)\n            elif isinstance(exc, InvalidHTTPVersion):\n                mesg = \"Invalid HTTP Version '%s'\" % str(exc)\n            elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)):\n                mesg = \"%s\" % str(exc)\n                if not req and hasattr(exc, \"req\"):\n                    req = exc.req  # for access log\n            elif isinstance(exc, LimitRequestLine):\n                mesg = \"%s\" % str(exc)\n            elif isinstance(exc, LimitRequestHeaders):\n                mesg = \"Error parsing headers: '%s'\" % str(exc)\n            elif isinstance(exc, InvalidProxyLine):\n                mesg = \"'%s'\" % str(exc)\n            elif isinstance(exc, ForbiddenProxyRequest):\n                reason = \"Forbidden\"\n                mesg = \"Request forbidden\"\n                status_int = 403\n            elif isinstance(exc, SSLError):\n                reason = \"Forbidden\"\n                mesg = \"'%s'\" % str(exc)\n                status_int = 403\n\n            msg = \"Invalid request from ip={ip}: {error}\"\n            self.log.debug(msg.format(ip=addr[0], error=str(exc)))\n        else:\n            if hasattr(req, \"uri\"):\n                self.log.exception(\"Error handling request %s\", req.uri)\n            status_int = 500\n            reason = \"Internal Server Error\"\n            mesg = \"\"\n\n        if req is not None:\n            request_time = datetime.now() - request_start\n            environ = default_environ(req, client, self.cfg)\n            environ['REMOTE_ADDR'] = addr[0]\n            environ['REMOTE_PORT'] = str(addr[1])\n            resp = Response(req, client, self.cfg)\n            resp.status = \"%s %s\" % (status_int, reason)\n            resp.response_length = len(mesg)\n            self.log.access(resp, req, environ, request_time)\n\n        try:\n            util.write_error(client, status_int, reason, mesg)\n        except:\n            self.log.debug(\"Failed to send error message.\")\n\n    def handle_winch(self, sig, fname):\n        # Ignore SIGWINCH in worker. Fixes a crash on OpenBSD.\n        return\n", "path": "gunicorn/workers/base.py"}]}