We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
race condition on lock :(
I think there is a race condition on 
**luigi/lock.py", line 93, in acquire_for**

```python
# Check if there is a pid file corresponding to this name
if not os.path.exists(pid_dir):
  os.mkdir(pid_dir)
```
between `if not [...]` and `mkdir` another process could have created the pid_dir resulting  in an unhandled OSError exception.

I think that ignore the exception if the folder exists will be enough, or perhaps just create the folder and say sorry if it was just there...


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `luigi/lock.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2012-2015 Spotify AB
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17 """
18 Locking functionality when launching things from the command line.
19 Uses a pidfile.
20 This prevents multiple identical workflows to be launched simultaneously.
21 """
22 from __future__ import print_function
23 
24 import hashlib
25 import os
26 import sys
27 from subprocess import Popen, PIPE
28 
29 from luigi import six
30 
31 
32 def getpcmd(pid):
33     """
34     Returns command of process.
35 
36     :param pid:
37     """
38     if os.name == "nt":
39         # Use wmic command instead of ps on Windows.
40         cmd = 'wmic path win32_process where ProcessID=%s get Commandline 2> nul' % (pid, )
41         with os.popen(cmd, 'r') as p:
42             lines = [line for line in p.readlines() if line.strip("\r\n ") != ""]
43             if lines:
44                 _, val = lines
45                 return val
46     elif sys.platform == "darwin":
47         # Use pgrep instead of /proc on macOS.
48         pidfile = ".%d.pid" % (pid, )
49         with open(pidfile, 'w') as f:
50             f.write(str(pid))
51         try:
52             p = Popen(['pgrep', '-lf', '-F', pidfile], stdout=PIPE)
53             stdout, _ = p.communicate()
54             line = stdout.decode('utf8').strip()
55             if line:
56                 _, scmd = line.split(' ', 1)
57                 return scmd
58         finally:
59             os.unlink(pidfile)
60     else:
61         # Use the /proc filesystem
62         # At least on android there have been some issues with not all
63         # process infos being readable. In these cases using the `ps` command
64         # worked. See the pull request at
65         # https://github.com/spotify/luigi/pull/1876
66         try:
67             with open('/proc/{0}/cmdline'.format(pid), 'r') as fh:
68                 if six.PY3:
69                     return fh.read().replace('\0', ' ').rstrip()
70                 else:
71                     return fh.read().replace('\0', ' ').decode('utf8').rstrip()
72         except IOError:
73             # the system may not allow reading the command line
74             # of a process owned by another user
75             pass
76 
77     # Fallback instead of None, for e.g. Cygwin where -o is an "unknown option" for the ps command:
78     return '[PROCESS_WITH_PID={}]'.format(pid)
79 
80 
81 def get_info(pid_dir, my_pid=None):
82     # Check the name and pid of this process
83     if my_pid is None:
84         my_pid = os.getpid()
85 
86     my_cmd = getpcmd(my_pid)
87     cmd_hash = my_cmd.encode('utf8')
88     pid_file = os.path.join(pid_dir, hashlib.md5(cmd_hash).hexdigest()) + '.pid'
89 
90     return my_pid, my_cmd, pid_file
91 
92 
93 def acquire_for(pid_dir, num_available=1, kill_signal=None):
94     """
95     Makes sure the process is only run once at the same time with the same name.
96 
97     Notice that we since we check the process name, different parameters to the same
98     command can spawn multiple processes at the same time, i.e. running
99     "/usr/bin/my_process" does not prevent anyone from launching
100     "/usr/bin/my_process --foo bar".
101     """
102 
103     my_pid, my_cmd, pid_file = get_info(pid_dir)
104 
105     # Check if there is a pid file corresponding to this name
106     if not os.path.exists(pid_dir):
107         os.mkdir(pid_dir)
108         os.chmod(pid_dir, 0o777)
109 
110     # Let variable "pids" be all pids who exist in the .pid-file who are still
111     # about running the same command.
112     pids = {pid for pid in _read_pids_file(pid_file) if getpcmd(pid) == my_cmd}
113 
114     if kill_signal is not None:
115         for pid in pids:
116             os.kill(pid, kill_signal)
117         print('Sent kill signal to Pids: {}'.format(pids))
118         # We allow for the killer to progress, yet we don't want these to stack
119         # up! So we only allow it once.
120         num_available += 1
121 
122     if len(pids) >= num_available:
123         # We are already running under a different pid
124         print('Pid(s) {} already running'.format(pids))
125         if kill_signal is not None:
126             print('Note: There have (probably) been 1 other "--take-lock"'
127                   ' process which continued to run! Probably no need to run'
128                   ' this one as well.')
129         return False
130 
131     _write_pids_file(pid_file, pids | {my_pid})
132 
133     return True
134 
135 
136 def _read_pids_file(pid_file):
137     # First setup a python 2 vs 3 compatibility
138     # http://stackoverflow.com/a/21368622/621449
139     try:
140         FileNotFoundError
141     except NameError:
142         # Should only happen on python 2
143         FileNotFoundError = IOError
144     # If the file happen to not exist, simply return
145     # an empty set()
146     try:
147         with open(pid_file, 'r') as f:
148             return {int(pid_str.strip()) for pid_str in f if pid_str.strip()}
149     except FileNotFoundError:
150         return set()
151 
152 
153 def _write_pids_file(pid_file, pids_set):
154     with open(pid_file, 'w') as f:
155         f.writelines('{}\n'.format(pid) for pid in pids_set)
156 
157     # Make the .pid-file writable by all (when the os allows for it)
158     if os.name != 'nt':
159         s = os.stat(pid_file)
160         if os.getuid() == s.st_uid:
161             os.chmod(pid_file, s.st_mode | 0o777)
162
```
--- 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/luigi/lock.py b/luigi/lock.py
--- a/luigi/lock.py
+++ b/luigi/lock.py
@@ -21,6 +21,7 @@
 """
 from __future__ import print_function
 
+import errno
 import hashlib
 import os
 import sys
@@ -102,10 +103,14 @@
 
     my_pid, my_cmd, pid_file = get_info(pid_dir)
 
-    # Check if there is a pid file corresponding to this name
-    if not os.path.exists(pid_dir):
+    # Create a pid file if it does not exist
+    try:
         os.mkdir(pid_dir)
         os.chmod(pid_dir, 0o777)
+    except OSError as exc:
+        if exc.errno != errno.EEXIST:
+            raise
+        pass
 
     # Let variable "pids" be all pids who exist in the .pid-file who are still
     # about running the same command.

{"golden_diff": "diff --git a/luigi/lock.py b/luigi/lock.py\n--- a/luigi/lock.py\n+++ b/luigi/lock.py\n@@ -21,6 +21,7 @@\n \"\"\"\n from __future__ import print_function\n \n+import errno\n import hashlib\n import os\n import sys\n@@ -102,10 +103,14 @@\n \n     my_pid, my_cmd, pid_file = get_info(pid_dir)\n \n-    # Check if there is a pid file corresponding to this name\n-    if not os.path.exists(pid_dir):\n+    # Create a pid file if it does not exist\n+    try:\n         os.mkdir(pid_dir)\n         os.chmod(pid_dir, 0o777)\n+    except OSError as exc:\n+        if exc.errno != errno.EEXIST:\n+            raise\n+        pass\n \n     # Let variable \"pids\" be all pids who exist in the .pid-file who are still\n     # about running the same command.\n", "issue": "race condition on lock :(\nI think there is a race condition on \r\n**luigi/lock.py\", line 93, in acquire_for**\r\n\r\n```python\r\n# Check if there is a pid file corresponding to this name\r\nif not os.path.exists(pid_dir):\r\n  os.mkdir(pid_dir)\r\n```\r\nbetween `if not [...]` and `mkdir` another process could have created the pid_dir resulting  in an unhandled OSError exception.\r\n\r\nI think that ignore the exception if the folder exists will be enough, or perhaps just create the folder and say sorry if it was just there...\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2012-2015 Spotify AB\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"\nLocking functionality when launching things from the command line.\nUses a pidfile.\nThis prevents multiple identical workflows to be launched simultaneously.\n\"\"\"\nfrom __future__ import print_function\n\nimport hashlib\nimport os\nimport sys\nfrom subprocess import Popen, PIPE\n\nfrom luigi import six\n\n\ndef getpcmd(pid):\n    \"\"\"\n    Returns command of process.\n\n    :param pid:\n    \"\"\"\n    if os.name == \"nt\":\n        # Use wmic command instead of ps on Windows.\n        cmd = 'wmic path win32_process where ProcessID=%s get Commandline 2> nul' % (pid, )\n        with os.popen(cmd, 'r') as p:\n            lines = [line for line in p.readlines() if line.strip(\"\\r\\n \") != \"\"]\n            if lines:\n                _, val = lines\n                return val\n    elif sys.platform == \"darwin\":\n        # Use pgrep instead of /proc on macOS.\n        pidfile = \".%d.pid\" % (pid, )\n        with open(pidfile, 'w') as f:\n            f.write(str(pid))\n        try:\n            p = Popen(['pgrep', '-lf', '-F', pidfile], stdout=PIPE)\n            stdout, _ = p.communicate()\n            line = stdout.decode('utf8').strip()\n            if line:\n                _, scmd = line.split(' ', 1)\n                return scmd\n        finally:\n            os.unlink(pidfile)\n    else:\n        # Use the /proc filesystem\n        # At least on android there have been some issues with not all\n        # process infos being readable. In these cases using the `ps` command\n        # worked. See the pull request at\n        # https://github.com/spotify/luigi/pull/1876\n        try:\n            with open('/proc/{0}/cmdline'.format(pid), 'r') as fh:\n                if six.PY3:\n                    return fh.read().replace('\\0', ' ').rstrip()\n                else:\n                    return fh.read().replace('\\0', ' ').decode('utf8').rstrip()\n        except IOError:\n            # the system may not allow reading the command line\n            # of a process owned by another user\n            pass\n\n    # Fallback instead of None, for e.g. Cygwin where -o is an \"unknown option\" for the ps command:\n    return '[PROCESS_WITH_PID={}]'.format(pid)\n\n\ndef get_info(pid_dir, my_pid=None):\n    # Check the name and pid of this process\n    if my_pid is None:\n        my_pid = os.getpid()\n\n    my_cmd = getpcmd(my_pid)\n    cmd_hash = my_cmd.encode('utf8')\n    pid_file = os.path.join(pid_dir, hashlib.md5(cmd_hash).hexdigest()) + '.pid'\n\n    return my_pid, my_cmd, pid_file\n\n\ndef acquire_for(pid_dir, num_available=1, kill_signal=None):\n    \"\"\"\n    Makes sure the process is only run once at the same time with the same name.\n\n    Notice that we since we check the process name, different parameters to the same\n    command can spawn multiple processes at the same time, i.e. running\n    \"/usr/bin/my_process\" does not prevent anyone from launching\n    \"/usr/bin/my_process --foo bar\".\n    \"\"\"\n\n    my_pid, my_cmd, pid_file = get_info(pid_dir)\n\n    # Check if there is a pid file corresponding to this name\n    if not os.path.exists(pid_dir):\n        os.mkdir(pid_dir)\n        os.chmod(pid_dir, 0o777)\n\n    # Let variable \"pids\" be all pids who exist in the .pid-file who are still\n    # about running the same command.\n    pids = {pid for pid in _read_pids_file(pid_file) if getpcmd(pid) == my_cmd}\n\n    if kill_signal is not None:\n        for pid in pids:\n            os.kill(pid, kill_signal)\n        print('Sent kill signal to Pids: {}'.format(pids))\n        # We allow for the killer to progress, yet we don't want these to stack\n        # up! So we only allow it once.\n        num_available += 1\n\n    if len(pids) >= num_available:\n        # We are already running under a different pid\n        print('Pid(s) {} already running'.format(pids))\n        if kill_signal is not None:\n            print('Note: There have (probably) been 1 other \"--take-lock\"'\n                  ' process which continued to run! Probably no need to run'\n                  ' this one as well.')\n        return False\n\n    _write_pids_file(pid_file, pids | {my_pid})\n\n    return True\n\n\ndef _read_pids_file(pid_file):\n    # First setup a python 2 vs 3 compatibility\n    # http://stackoverflow.com/a/21368622/621449\n    try:\n        FileNotFoundError\n    except NameError:\n        # Should only happen on python 2\n        FileNotFoundError = IOError\n    # If the file happen to not exist, simply return\n    # an empty set()\n    try:\n        with open(pid_file, 'r') as f:\n            return {int(pid_str.strip()) for pid_str in f if pid_str.strip()}\n    except FileNotFoundError:\n        return set()\n\n\ndef _write_pids_file(pid_file, pids_set):\n    with open(pid_file, 'w') as f:\n        f.writelines('{}\\n'.format(pid) for pid in pids_set)\n\n    # Make the .pid-file writable by all (when the os allows for it)\n    if os.name != 'nt':\n        s = os.stat(pid_file)\n        if os.getuid() == s.st_uid:\n            os.chmod(pid_file, s.st_mode | 0o777)\n", "path": "luigi/lock.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2012-2015 Spotify AB\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"\nLocking functionality when launching things from the command line.\nUses a pidfile.\nThis prevents multiple identical workflows to be launched simultaneously.\n\"\"\"\nfrom __future__ import print_function\n\nimport errno\nimport hashlib\nimport os\nimport sys\nfrom subprocess import Popen, PIPE\n\nfrom luigi import six\n\n\ndef getpcmd(pid):\n    \"\"\"\n    Returns command of process.\n\n    :param pid:\n    \"\"\"\n    if os.name == \"nt\":\n        # Use wmic command instead of ps on Windows.\n        cmd = 'wmic path win32_process where ProcessID=%s get Commandline 2> nul' % (pid, )\n        with os.popen(cmd, 'r') as p:\n            lines = [line for line in p.readlines() if line.strip(\"\\r\\n \") != \"\"]\n            if lines:\n                _, val = lines\n                return val\n    elif sys.platform == \"darwin\":\n        # Use pgrep instead of /proc on macOS.\n        pidfile = \".%d.pid\" % (pid, )\n        with open(pidfile, 'w') as f:\n            f.write(str(pid))\n        try:\n            p = Popen(['pgrep', '-lf', '-F', pidfile], stdout=PIPE)\n            stdout, _ = p.communicate()\n            line = stdout.decode('utf8').strip()\n            if line:\n                _, scmd = line.split(' ', 1)\n                return scmd\n        finally:\n            os.unlink(pidfile)\n    else:\n        # Use the /proc filesystem\n        # At least on android there have been some issues with not all\n        # process infos being readable. In these cases using the `ps` command\n        # worked. See the pull request at\n        # https://github.com/spotify/luigi/pull/1876\n        try:\n            with open('/proc/{0}/cmdline'.format(pid), 'r') as fh:\n                if six.PY3:\n                    return fh.read().replace('\\0', ' ').rstrip()\n                else:\n                    return fh.read().replace('\\0', ' ').decode('utf8').rstrip()\n        except IOError:\n            # the system may not allow reading the command line\n            # of a process owned by another user\n            pass\n\n    # Fallback instead of None, for e.g. Cygwin where -o is an \"unknown option\" for the ps command:\n    return '[PROCESS_WITH_PID={}]'.format(pid)\n\n\ndef get_info(pid_dir, my_pid=None):\n    # Check the name and pid of this process\n    if my_pid is None:\n        my_pid = os.getpid()\n\n    my_cmd = getpcmd(my_pid)\n    cmd_hash = my_cmd.encode('utf8')\n    pid_file = os.path.join(pid_dir, hashlib.md5(cmd_hash).hexdigest()) + '.pid'\n\n    return my_pid, my_cmd, pid_file\n\n\ndef acquire_for(pid_dir, num_available=1, kill_signal=None):\n    \"\"\"\n    Makes sure the process is only run once at the same time with the same name.\n\n    Notice that we since we check the process name, different parameters to the same\n    command can spawn multiple processes at the same time, i.e. running\n    \"/usr/bin/my_process\" does not prevent anyone from launching\n    \"/usr/bin/my_process --foo bar\".\n    \"\"\"\n\n    my_pid, my_cmd, pid_file = get_info(pid_dir)\n\n    # Create a pid file if it does not exist\n    try:\n        os.mkdir(pid_dir)\n        os.chmod(pid_dir, 0o777)\n    except OSError as exc:\n        if exc.errno != errno.EEXIST:\n            raise\n        pass\n\n    # Let variable \"pids\" be all pids who exist in the .pid-file who are still\n    # about running the same command.\n    pids = {pid for pid in _read_pids_file(pid_file) if getpcmd(pid) == my_cmd}\n\n    if kill_signal is not None:\n        for pid in pids:\n            os.kill(pid, kill_signal)\n        print('Sent kill signal to Pids: {}'.format(pids))\n        # We allow for the killer to progress, yet we don't want these to stack\n        # up! So we only allow it once.\n        num_available += 1\n\n    if len(pids) >= num_available:\n        # We are already running under a different pid\n        print('Pid(s) {} already running'.format(pids))\n        if kill_signal is not None:\n            print('Note: There have (probably) been 1 other \"--take-lock\"'\n                  ' process which continued to run! Probably no need to run'\n                  ' this one as well.')\n        return False\n\n    _write_pids_file(pid_file, pids | {my_pid})\n\n    return True\n\n\ndef _read_pids_file(pid_file):\n    # First setup a python 2 vs 3 compatibility\n    # http://stackoverflow.com/a/21368622/621449\n    try:\n        FileNotFoundError\n    except NameError:\n        # Should only happen on python 2\n        FileNotFoundError = IOError\n    # If the file happen to not exist, simply return\n    # an empty set()\n    try:\n        with open(pid_file, 'r') as f:\n            return {int(pid_str.strip()) for pid_str in f if pid_str.strip()}\n    except FileNotFoundError:\n        return set()\n\n\ndef _write_pids_file(pid_file, pids_set):\n    with open(pid_file, 'w') as f:\n        f.writelines('{}\\n'.format(pid) for pid in pids_set)\n\n    # Make the .pid-file writable by all (when the os allows for it)\n    if os.name != 'nt':\n        s = os.stat(pid_file)\n        if os.getuid() == s.st_uid:\n            os.chmod(pid_file, s.st_mode | 0o777)\n", "path": "luigi/lock.py"}]}