We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
file-system race condition while testing with mkdocs serve
when mkdocs serve is shutting down, it cleans up after itself removing the temporary directory created earlier.

the condition whether the directory needs to be removed is unchecked and prone to a file system race condition (shared resource).

given the directory is already removed on the file-system while shutting down, mkdocs serve throws an exception and exits in failure.

this error can be safely defined out of existence by removing the temporary directory only if it exists, will suggest a PR for this report. /E: created #2421

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mkdocs/commands/serve.py`
Content:
```
1 import logging
2 import shutil
3 import tempfile
4 
5 from os.path import isfile, join
6 from mkdocs.commands.build import build
7 from mkdocs.config import load_config
8 from mkdocs.exceptions import Abort
9 from mkdocs.livereload import LiveReloadServer
10 
11 log = logging.getLogger(__name__)
12 
13 
14 def serve(config_file=None, dev_addr=None, strict=None, theme=None,
15           theme_dir=None, livereload='livereload', watch_theme=False, **kwargs):
16     """
17     Start the MkDocs development server
18 
19     By default it will serve the documentation on http://localhost:8000/ and
20     it will rebuild the documentation and refresh the page automatically
21     whenever a file is edited.
22     """
23 
24     # Create a temporary build directory, and set some options to serve it
25     # PY2 returns a byte string by default. The Unicode prefix ensures a Unicode
26     # string is returned. And it makes MkDocs temp dirs easier to identify.
27     site_dir = tempfile.mkdtemp(prefix='mkdocs_')
28 
29     def builder():
30         log.info("Building documentation...")
31         config = load_config(
32             config_file=config_file,
33             dev_addr=dev_addr,
34             strict=strict,
35             theme=theme,
36             theme_dir=theme_dir,
37             site_dir=site_dir,
38             **kwargs
39         )
40         # Override a few config settings after validation
41         config['site_url'] = 'http://{}/'.format(config['dev_addr'])
42 
43         live_server = livereload in ['dirty', 'livereload']
44         dirty = livereload == 'dirty'
45         build(config, live_server=live_server, dirty=dirty)
46         return config
47 
48     try:
49         # Perform the initial build
50         config = builder()
51 
52         host, port = config['dev_addr']
53 
54         server = LiveReloadServer(builder=builder, host=host, port=port, root=site_dir)
55 
56         def error_handler(code):
57             if code in (404, 500):
58                 error_page = join(site_dir, f'{code}.html')
59                 if isfile(error_page):
60                     with open(error_page, 'rb') as f:
61                         return f.read()
62 
63         server.error_handler = error_handler
64 
65         if livereload in ['livereload', 'dirty']:
66             # Watch the documentation files, the config file and the theme files.
67             server.watch(config['docs_dir'])
68             server.watch(config['config_file_path'])
69 
70             if watch_theme:
71                 for d in config['theme'].dirs:
72                     server.watch(d)
73 
74             # Run `serve` plugin events.
75             server = config['plugins'].run_event('serve', server, config=config, builder=builder)
76 
77         try:
78             server.serve()
79         except KeyboardInterrupt:
80             log.info("Shutting down...")
81         finally:
82             server.shutdown()
83     except OSError as e:  # pragma: no cover
84         # Avoid ugly, unhelpful traceback
85         raise Abort(str(e))
86     finally:
87         shutil.rmtree(site_dir)
88
```
--- 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/mkdocs/commands/serve.py b/mkdocs/commands/serve.py
--- a/mkdocs/commands/serve.py
+++ b/mkdocs/commands/serve.py
@@ -2,7 +2,7 @@
 import shutil
 import tempfile
 
-from os.path import isfile, join
+from os.path import isdir, isfile, join
 from mkdocs.commands.build import build
 from mkdocs.config import load_config
 from mkdocs.exceptions import Abort
@@ -84,4 +84,5 @@
         # Avoid ugly, unhelpful traceback
         raise Abort(str(e))
     finally:
-        shutil.rmtree(site_dir)
+        if isdir(site_dir):
+            shutil.rmtree(site_dir)

{"golden_diff": "diff --git a/mkdocs/commands/serve.py b/mkdocs/commands/serve.py\n--- a/mkdocs/commands/serve.py\n+++ b/mkdocs/commands/serve.py\n@@ -2,7 +2,7 @@\n import shutil\n import tempfile\n \n-from os.path import isfile, join\n+from os.path import isdir, isfile, join\n from mkdocs.commands.build import build\n from mkdocs.config import load_config\n from mkdocs.exceptions import Abort\n@@ -84,4 +84,5 @@\n         # Avoid ugly, unhelpful traceback\n         raise Abort(str(e))\n     finally:\n-        shutil.rmtree(site_dir)\n+        if isdir(site_dir):\n+            shutil.rmtree(site_dir)\n", "issue": "file-system race condition while testing with mkdocs serve\nwhen mkdocs serve is shutting down, it cleans up after itself removing the temporary directory created earlier.\r\n\r\nthe condition whether the directory needs to be removed is unchecked and prone to a file system race condition (shared resource).\r\n\r\ngiven the directory is already removed on the file-system while shutting down, mkdocs serve throws an exception and exits in failure.\r\n\r\nthis error can be safely defined out of existence by removing the temporary directory only if it exists, will suggest a PR for this report. /E: created #2421\n", "before_files": [{"content": "import logging\nimport shutil\nimport tempfile\n\nfrom os.path import isfile, join\nfrom mkdocs.commands.build import build\nfrom mkdocs.config import load_config\nfrom mkdocs.exceptions import Abort\nfrom mkdocs.livereload import LiveReloadServer\n\nlog = logging.getLogger(__name__)\n\n\ndef serve(config_file=None, dev_addr=None, strict=None, theme=None,\n          theme_dir=None, livereload='livereload', watch_theme=False, **kwargs):\n    \"\"\"\n    Start the MkDocs development server\n\n    By default it will serve the documentation on http://localhost:8000/ and\n    it will rebuild the documentation and refresh the page automatically\n    whenever a file is edited.\n    \"\"\"\n\n    # Create a temporary build directory, and set some options to serve it\n    # PY2 returns a byte string by default. The Unicode prefix ensures a Unicode\n    # string is returned. And it makes MkDocs temp dirs easier to identify.\n    site_dir = tempfile.mkdtemp(prefix='mkdocs_')\n\n    def builder():\n        log.info(\"Building documentation...\")\n        config = load_config(\n            config_file=config_file,\n            dev_addr=dev_addr,\n            strict=strict,\n            theme=theme,\n            theme_dir=theme_dir,\n            site_dir=site_dir,\n            **kwargs\n        )\n        # Override a few config settings after validation\n        config['site_url'] = 'http://{}/'.format(config['dev_addr'])\n\n        live_server = livereload in ['dirty', 'livereload']\n        dirty = livereload == 'dirty'\n        build(config, live_server=live_server, dirty=dirty)\n        return config\n\n    try:\n        # Perform the initial build\n        config = builder()\n\n        host, port = config['dev_addr']\n\n        server = LiveReloadServer(builder=builder, host=host, port=port, root=site_dir)\n\n        def error_handler(code):\n            if code in (404, 500):\n                error_page = join(site_dir, f'{code}.html')\n                if isfile(error_page):\n                    with open(error_page, 'rb') as f:\n                        return f.read()\n\n        server.error_handler = error_handler\n\n        if livereload in ['livereload', 'dirty']:\n            # Watch the documentation files, the config file and the theme files.\n            server.watch(config['docs_dir'])\n            server.watch(config['config_file_path'])\n\n            if watch_theme:\n                for d in config['theme'].dirs:\n                    server.watch(d)\n\n            # Run `serve` plugin events.\n            server = config['plugins'].run_event('serve', server, config=config, builder=builder)\n\n        try:\n            server.serve()\n        except KeyboardInterrupt:\n            log.info(\"Shutting down...\")\n        finally:\n            server.shutdown()\n    except OSError as e:  # pragma: no cover\n        # Avoid ugly, unhelpful traceback\n        raise Abort(str(e))\n    finally:\n        shutil.rmtree(site_dir)\n", "path": "mkdocs/commands/serve.py"}], "after_files": [{"content": "import logging\nimport shutil\nimport tempfile\n\nfrom os.path import isdir, isfile, join\nfrom mkdocs.commands.build import build\nfrom mkdocs.config import load_config\nfrom mkdocs.exceptions import Abort\nfrom mkdocs.livereload import LiveReloadServer\n\nlog = logging.getLogger(__name__)\n\n\ndef serve(config_file=None, dev_addr=None, strict=None, theme=None,\n          theme_dir=None, livereload='livereload', watch_theme=False, **kwargs):\n    \"\"\"\n    Start the MkDocs development server\n\n    By default it will serve the documentation on http://localhost:8000/ and\n    it will rebuild the documentation and refresh the page automatically\n    whenever a file is edited.\n    \"\"\"\n\n    # Create a temporary build directory, and set some options to serve it\n    # PY2 returns a byte string by default. The Unicode prefix ensures a Unicode\n    # string is returned. And it makes MkDocs temp dirs easier to identify.\n    site_dir = tempfile.mkdtemp(prefix='mkdocs_')\n\n    def builder():\n        log.info(\"Building documentation...\")\n        config = load_config(\n            config_file=config_file,\n            dev_addr=dev_addr,\n            strict=strict,\n            theme=theme,\n            theme_dir=theme_dir,\n            site_dir=site_dir,\n            **kwargs\n        )\n        # Override a few config settings after validation\n        config['site_url'] = 'http://{}/'.format(config['dev_addr'])\n\n        live_server = livereload in ['dirty', 'livereload']\n        dirty = livereload == 'dirty'\n        build(config, live_server=live_server, dirty=dirty)\n        return config\n\n    try:\n        # Perform the initial build\n        config = builder()\n\n        host, port = config['dev_addr']\n\n        server = LiveReloadServer(builder=builder, host=host, port=port, root=site_dir)\n\n        def error_handler(code):\n            if code in (404, 500):\n                error_page = join(site_dir, f'{code}.html')\n                if isfile(error_page):\n                    with open(error_page, 'rb') as f:\n                        return f.read()\n\n        server.error_handler = error_handler\n\n        if livereload in ['livereload', 'dirty']:\n            # Watch the documentation files, the config file and the theme files.\n            server.watch(config['docs_dir'])\n            server.watch(config['config_file_path'])\n\n            if watch_theme:\n                for d in config['theme'].dirs:\n                    server.watch(d)\n\n            # Run `serve` plugin events.\n            server = config['plugins'].run_event('serve', server, config=config, builder=builder)\n\n        try:\n            server.serve()\n        except KeyboardInterrupt:\n            log.info(\"Shutting down...\")\n        finally:\n            server.shutdown()\n    except OSError as e:  # pragma: no cover\n        # Avoid ugly, unhelpful traceback\n        raise Abort(str(e))\n    finally:\n        if isdir(site_dir):\n            shutil.rmtree(site_dir)\n", "path": "mkdocs/commands/serve.py"}]}