We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Windows phantomjs not killed on selenium termination
I reinstalled a fresh python environment on windows with python 3.7 and pythonenv
I use only pip for package dependencies
When I tried to run tests some failed because temp files were locked.
<img width="726" alt="win32error" src="https://user-images.githubusercontent.com/18531147/54091987-214f4580-4387-11e9-9584-6a117a356ad2.png">
<img width="257" alt="test_failures" src="https://user-images.githubusercontent.com/18531147/54091989-24e2cc80-4387-11e9-9c42-3573dabd1813.PNG">


When driver terminate phantomjs is not correctly killed:
<img width="294" alt="proc_pantomjs" src="https://user-images.githubusercontent.com/18531147/54092002-45128b80-4387-11e9-9967-bf74b1e41bd7.PNG">


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/io/webdriver.py`
Content:
```
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.
3 # All rights reserved.
4 #
5 # The full license is in the file LICENSE.txt, distributed with this software.
6 #-----------------------------------------------------------------------------
7 '''
8 
9 '''
10 
11 #-----------------------------------------------------------------------------
12 # Boilerplate
13 #-----------------------------------------------------------------------------
14 from __future__ import absolute_import, division, print_function, unicode_literals
15 
16 import logging
17 log = logging.getLogger(__name__)
18 
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22 
23 # Standard library imports
24 import atexit
25 import signal
26 import warnings
27 from os.path import devnull
28 
29 # External imports
30 
31 # Bokeh imports
32 from ..util.dependencies import import_required, detect_phantomjs
33 
34 #-----------------------------------------------------------------------------
35 # Globals and constants
36 #-----------------------------------------------------------------------------
37 
38 __all__ = (
39     'create_phantomjs_webdriver',
40     'terminate_webdriver',
41     'webdriver_control',
42 )
43 
44 #-----------------------------------------------------------------------------
45 # General API
46 #-----------------------------------------------------------------------------
47 
48 #-----------------------------------------------------------------------------
49 # Dev API
50 #-----------------------------------------------------------------------------
51 
52 def create_phantomjs_webdriver():
53     with warnings.catch_warnings():
54         warnings.filterwarnings("ignore", ".*", UserWarning, "selenium.webdriver.phantomjs.webdriver")
55 
56         webdriver = import_required('selenium.webdriver',
57                                     'To use bokeh.io image export functions you need selenium ' +
58                                     '("conda install -c bokeh selenium" or "pip install selenium")')
59 
60         phantomjs_path = detect_phantomjs()
61         return webdriver.PhantomJS(executable_path=phantomjs_path, service_log_path=devnull)
62 
63 def terminate_webdriver(driver):
64     if driver.name == "phantomjs":
65         # https://github.com/seleniumhq/selenium/issues/767
66         if driver.service.process:
67             driver.service.process.send_signal(signal.SIGTERM)
68 
69     try:
70         driver.quit()
71     except (IOError, OSError): # IOError for Python 2.7
72         pass
73 
74 #-----------------------------------------------------------------------------
75 # Private API
76 #-----------------------------------------------------------------------------
77 
78 class _WebdriverState(object):
79     '''
80 
81     '''
82 
83     def __init__(self, reuse=True, kind="phantomjs"):
84         self.reuse = reuse
85         self.kind = kind
86         self.current = None
87 
88     def reset(self):
89         if self.current is not None:
90             terminate_webdriver(self.current)
91             self.current = None
92 
93     def get(self):
94         if not self.reuse or self.current is None:
95             if self.current is not None:
96                 terminate_webdriver(self.current)
97             self.current = self.create()
98         return self.current
99 
100     def create(self):
101         if self.kind == "phantomjs":
102             return create_phantomjs_webdriver()
103         raise ValueError("Unknown webdriver kind %r" % self.kind)
104 
105     @property
106     def reuse(self):
107         return self._reuse
108 
109     @reuse.setter
110     def reuse(self, value):
111         self._reuse = value
112 
113     @property
114     def kind(self):
115         return self._kind
116 
117     @kind.setter
118     def kind(self, value):
119         # TODO (bev) enum/value check when more are added
120         self._kind = value
121 
122 #-----------------------------------------------------------------------------
123 # Code
124 #-----------------------------------------------------------------------------
125 
126 
127 webdriver_control = _WebdriverState()
128 
129 atexit.register(lambda: webdriver_control.reset())
130
```
--- 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/bokeh/io/webdriver.py b/bokeh/io/webdriver.py
--- a/bokeh/io/webdriver.py
+++ b/bokeh/io/webdriver.py
@@ -21,6 +21,7 @@
 #-----------------------------------------------------------------------------
 
 # Standard library imports
+import sys
 import atexit
 import signal
 import warnings
@@ -29,7 +30,7 @@
 # External imports
 
 # Bokeh imports
-from ..util.dependencies import import_required, detect_phantomjs
+from ..util.dependencies import import_required, detect_phantomjs, import_optional
 
 #-----------------------------------------------------------------------------
 # Globals and constants
@@ -49,6 +50,20 @@
 # Dev API
 #-----------------------------------------------------------------------------
 
+
+def kill_proc_tree(pid, including_parent=True):
+    psutil = import_optional('psutil')
+    if psutil is not None:
+        parent = psutil.Process(pid)
+        children = parent.children(recursive=True)
+        for child in children:
+            child.kill()
+        psutil.wait_procs(children)
+        if including_parent:
+            parent.kill()
+            parent.wait(5)
+
+
 def create_phantomjs_webdriver():
     with warnings.catch_warnings():
         warnings.filterwarnings("ignore", ".*", UserWarning, "selenium.webdriver.phantomjs.webdriver")
@@ -60,21 +75,25 @@
         phantomjs_path = detect_phantomjs()
         return webdriver.PhantomJS(executable_path=phantomjs_path, service_log_path=devnull)
 
+
 def terminate_webdriver(driver):
     if driver.name == "phantomjs":
         # https://github.com/seleniumhq/selenium/issues/767
         if driver.service.process:
+            if sys.platform == 'win32':
+                kill_proc_tree(driver.service.process.pid, including_parent=False)
             driver.service.process.send_signal(signal.SIGTERM)
 
     try:
         driver.quit()
-    except (IOError, OSError): # IOError for Python 2.7
+    except (IOError, OSError):  # IOError for Python 2.7
         pass
 
 #-----------------------------------------------------------------------------
 # Private API
 #-----------------------------------------------------------------------------
 
+
 class _WebdriverState(object):
     '''

{"golden_diff": "diff --git a/bokeh/io/webdriver.py b/bokeh/io/webdriver.py\n--- a/bokeh/io/webdriver.py\n+++ b/bokeh/io/webdriver.py\n@@ -21,6 +21,7 @@\n #-----------------------------------------------------------------------------\n \n # Standard library imports\n+import sys\n import atexit\n import signal\n import warnings\n@@ -29,7 +30,7 @@\n # External imports\n \n # Bokeh imports\n-from ..util.dependencies import import_required, detect_phantomjs\n+from ..util.dependencies import import_required, detect_phantomjs, import_optional\n \n #-----------------------------------------------------------------------------\n # Globals and constants\n@@ -49,6 +50,20 @@\n # Dev API\n #-----------------------------------------------------------------------------\n \n+\n+def kill_proc_tree(pid, including_parent=True):\n+    psutil = import_optional('psutil')\n+    if psutil is not None:\n+        parent = psutil.Process(pid)\n+        children = parent.children(recursive=True)\n+        for child in children:\n+            child.kill()\n+        psutil.wait_procs(children)\n+        if including_parent:\n+            parent.kill()\n+            parent.wait(5)\n+\n+\n def create_phantomjs_webdriver():\n     with warnings.catch_warnings():\n         warnings.filterwarnings(\"ignore\", \".*\", UserWarning, \"selenium.webdriver.phantomjs.webdriver\")\n@@ -60,21 +75,25 @@\n         phantomjs_path = detect_phantomjs()\n         return webdriver.PhantomJS(executable_path=phantomjs_path, service_log_path=devnull)\n \n+\n def terminate_webdriver(driver):\n     if driver.name == \"phantomjs\":\n         # https://github.com/seleniumhq/selenium/issues/767\n         if driver.service.process:\n+            if sys.platform == 'win32':\n+                kill_proc_tree(driver.service.process.pid, including_parent=False)\n             driver.service.process.send_signal(signal.SIGTERM)\n \n     try:\n         driver.quit()\n-    except (IOError, OSError): # IOError for Python 2.7\n+    except (IOError, OSError):  # IOError for Python 2.7\n         pass\n \n #-----------------------------------------------------------------------------\n # Private API\n #-----------------------------------------------------------------------------\n \n+\n class _WebdriverState(object):\n     '''\n", "issue": "Windows phantomjs not killed on selenium termination\nI reinstalled a fresh python environment on windows with python 3.7 and pythonenv\r\nI use only pip for package dependencies\r\nWhen I tried to run tests some failed because temp files were locked.\r\n<img width=\"726\" alt=\"win32error\" src=\"https://user-images.githubusercontent.com/18531147/54091987-214f4580-4387-11e9-9584-6a117a356ad2.png\">\r\n<img width=\"257\" alt=\"test_failures\" src=\"https://user-images.githubusercontent.com/18531147/54091989-24e2cc80-4387-11e9-9c42-3573dabd1813.PNG\">\r\n\r\n\r\nWhen driver terminate phantomjs is not correctly killed:\r\n<img width=\"294\" alt=\"proc_pantomjs\" src=\"https://user-images.githubusercontent.com/18531147/54092002-45128b80-4387-11e9-9967-bf74b1e41bd7.PNG\">\r\n\n", "before_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n'''\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nlog = logging.getLogger(__name__)\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\n# Standard library imports\nimport atexit\nimport signal\nimport warnings\nfrom os.path import devnull\n\n# External imports\n\n# Bokeh imports\nfrom ..util.dependencies import import_required, detect_phantomjs\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\n__all__ = (\n    'create_phantomjs_webdriver',\n    'terminate_webdriver',\n    'webdriver_control',\n)\n\n#-----------------------------------------------------------------------------\n# General API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Dev API\n#-----------------------------------------------------------------------------\n\ndef create_phantomjs_webdriver():\n    with warnings.catch_warnings():\n        warnings.filterwarnings(\"ignore\", \".*\", UserWarning, \"selenium.webdriver.phantomjs.webdriver\")\n\n        webdriver = import_required('selenium.webdriver',\n                                    'To use bokeh.io image export functions you need selenium ' +\n                                    '(\"conda install -c bokeh selenium\" or \"pip install selenium\")')\n\n        phantomjs_path = detect_phantomjs()\n        return webdriver.PhantomJS(executable_path=phantomjs_path, service_log_path=devnull)\n\ndef terminate_webdriver(driver):\n    if driver.name == \"phantomjs\":\n        # https://github.com/seleniumhq/selenium/issues/767\n        if driver.service.process:\n            driver.service.process.send_signal(signal.SIGTERM)\n\n    try:\n        driver.quit()\n    except (IOError, OSError): # IOError for Python 2.7\n        pass\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\nclass _WebdriverState(object):\n    '''\n\n    '''\n\n    def __init__(self, reuse=True, kind=\"phantomjs\"):\n        self.reuse = reuse\n        self.kind = kind\n        self.current = None\n\n    def reset(self):\n        if self.current is not None:\n            terminate_webdriver(self.current)\n            self.current = None\n\n    def get(self):\n        if not self.reuse or self.current is None:\n            if self.current is not None:\n                terminate_webdriver(self.current)\n            self.current = self.create()\n        return self.current\n\n    def create(self):\n        if self.kind == \"phantomjs\":\n            return create_phantomjs_webdriver()\n        raise ValueError(\"Unknown webdriver kind %r\" % self.kind)\n\n    @property\n    def reuse(self):\n        return self._reuse\n\n    @reuse.setter\n    def reuse(self, value):\n        self._reuse = value\n\n    @property\n    def kind(self):\n        return self._kind\n\n    @kind.setter\n    def kind(self, value):\n        # TODO (bev) enum/value check when more are added\n        self._kind = value\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n\n\nwebdriver_control = _WebdriverState()\n\natexit.register(lambda: webdriver_control.reset())\n", "path": "bokeh/io/webdriver.py"}], "after_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n'''\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nlog = logging.getLogger(__name__)\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\n# Standard library imports\nimport sys\nimport atexit\nimport signal\nimport warnings\nfrom os.path import devnull\n\n# External imports\n\n# Bokeh imports\nfrom ..util.dependencies import import_required, detect_phantomjs, import_optional\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\n__all__ = (\n    'create_phantomjs_webdriver',\n    'terminate_webdriver',\n    'webdriver_control',\n)\n\n#-----------------------------------------------------------------------------\n# General API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Dev API\n#-----------------------------------------------------------------------------\n\n\ndef kill_proc_tree(pid, including_parent=True):\n    psutil = import_optional('psutil')\n    if psutil is not None:\n        parent = psutil.Process(pid)\n        children = parent.children(recursive=True)\n        for child in children:\n            child.kill()\n        psutil.wait_procs(children)\n        if including_parent:\n            parent.kill()\n            parent.wait(5)\n\n\ndef create_phantomjs_webdriver():\n    with warnings.catch_warnings():\n        warnings.filterwarnings(\"ignore\", \".*\", UserWarning, \"selenium.webdriver.phantomjs.webdriver\")\n\n        webdriver = import_required('selenium.webdriver',\n                                    'To use bokeh.io image export functions you need selenium ' +\n                                    '(\"conda install -c bokeh selenium\" or \"pip install selenium\")')\n\n        phantomjs_path = detect_phantomjs()\n        return webdriver.PhantomJS(executable_path=phantomjs_path, service_log_path=devnull)\n\n\ndef terminate_webdriver(driver):\n    if driver.name == \"phantomjs\":\n        # https://github.com/seleniumhq/selenium/issues/767\n        if driver.service.process:\n            if sys.platform == 'win32':\n                kill_proc_tree(driver.service.process.pid, including_parent=False)\n            driver.service.process.send_signal(signal.SIGTERM)\n\n    try:\n        driver.quit()\n    except (IOError, OSError):  # IOError for Python 2.7\n        pass\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\n\nclass _WebdriverState(object):\n    '''\n\n    '''\n\n    def __init__(self, reuse=True, kind=\"phantomjs\"):\n        self.reuse = reuse\n        self.kind = kind\n        self.current = None\n\n    def reset(self):\n        if self.current is not None:\n            terminate_webdriver(self.current)\n            self.current = None\n\n    def get(self):\n        if not self.reuse or self.current is None:\n            if self.current is not None:\n                terminate_webdriver(self.current)\n            self.current = self.create()\n        return self.current\n\n    def create(self):\n        if self.kind == \"phantomjs\":\n            return create_phantomjs_webdriver()\n        raise ValueError(\"Unknown webdriver kind %r\" % self.kind)\n\n    @property\n    def reuse(self):\n        return self._reuse\n\n    @reuse.setter\n    def reuse(self, value):\n        self._reuse = value\n\n    @property\n    def kind(self):\n        return self._kind\n\n    @kind.setter\n    def kind(self, value):\n        # TODO (bev) enum/value check when more are added\n        self._kind = value\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n\n\nwebdriver_control = _WebdriverState()\n\natexit.register(lambda: webdriver_control.reset())\n", "path": "bokeh/io/webdriver.py"}]}