-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IOError: (9, 'Bad file descriptor') gunicorn-19.5.0 #1259
Comments
Can you paste the full error log you get? |
also what does mean:
Do you try to embed gunicorn? |
@papachoco forget my second comment :) On which OS do you get the error right now? |
The error is being seen on OS X, El Capitan, I believe. |
I suspect you've already done this, but I can also reproduce the error on OS X. There is no specific error message (which seems wrong), instead you just get this:
If I edit
|
@jamadden actually i'm only reproducing it on osx :) this is why I ask. So I guess the lock needs to be handled diffrently on OSX but not sure how yet. |
As far as I can determine experimentally, OS X just doesn't support locking on unix domain sockets. The call to
0x7 is our fileno, 0x8 is F_SETLK, and errno 9 is EBADF. Here's a minimal C program that demonstrates the same failure on OS X: #include <fcntl.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
printf("Opened fd %d\n", fd);
struct sockaddr_un addr = { .sun_path = "/tmp/sock.sock"};
addr.sun_len = strlen(addr.sun_path); // OS X Only!
addr.sun_family = PF_UNIX;
int bound = bind(fd, &addr, sizeof(addr));
printf("Bound %d\n", bound);
struct flock lock = {0, 0, getpid(), F_RDLCK, 0};
int lock_res = fcntl(fd, F_SETLK, &lock);
printf("Lock %d\n", lock_res);
if (lock_res < 0)
perror("Failed to lock:");
return 0;
} When run, this outputs:
I'm looking for where this is documented. The closest I've got so far is the bottom of the
|
The POSIX specification for
A socket is not a regular file, so locking isn't required to be supported on them. |
Changing
man flock says:
So I guess we just can't do this on OS X with the socket descriptor. We could potentially create a regular file next to the socket to lock on... |
I also get the same failure on FreeBSD, so probably any member of the BSD family is affected. |
I also get the same failure on Solaris. I think locking on sockets is not very portable. |
@jamadden right. I will have a closer look today on that topic. We need a more portable way to fix #1185. The code responsible of unlinking is the following: The thing I don't understand right now is why the file is deleted while another process is using it. Reading unix(7) [1]:
and the related unlink(2) [2] manual:
So as I read it the file shouldn't be deleted if the new process created via [1] http://linux.die.net/man/7/unix |
The file isn't deleted, but the name of the file is. That is, the data (if there were any) still exists on disk, and can be read/written with open file descriptors, but trying to # lnk.py
import os
# get a filename
tname = os.tmpnam()
# open and create it
tfile = open(tname, 'w')
rpipe, wpipe = os.pipe()
pid = os.fork()
if pid != 0:
# parent
os.read(rpipe, 1)
try:
print(os.stat(tname))
finally:
os.wait()
else:
# child
# remove the file
# *that we have open*
os.unlink(tname)
# alert the parent
os.write(wpipe, b'.')
# die After the second process unlinks the name, when the first process tries to
This is why functions that take a file descriptor, like So for #1185, we have a race condition:
After 3., the file name is gone. The new arbiter is still connected to the same file as the first arbiter was, but anyone subsequently trying to |
Or, here's the missing (implied) text from the manual:
|
@jamadden indeed. In fact, the thing I forgot , is the case where an external application try to reopen this socket file via its name which doesn't exist anymore.... so the simplest solution fix that comes to my mind for now would be the following:
we could then using The workflow will be the following:
Other way would be retrieving from the system the number of processes actually using the file descriptor. This solution would be the best imo but I'm not sure how it's feasible cross-platform. Thoughts? |
gevent does that in its test cases, and I can tell you that it's not portable :) The That said, I'm not sure the refcount is needed. Wouldn't the same basic read/exclusive lock strategy work for the lock file, just like we were trying to do on the socket? I mean, we're going to have to take exclusive locks to increment/decrement the count safely as it is. I also think it's safest/simplest to not ever try to unlink the lock file, just use the locks. Each process Of course, people may also object to the extra file just existing at all; I wonder if they'll want an option to control where it lives? |
we can create a new config setting for it. Right now i'm asking myself if wee need to create a new lockfile or improve the pidfile handling ? |
This change add proper file locking to gunicorn. By default "gunicorn.lock" is created in the temporary directory when a unix socket is bound. In case someone want to fix the lock file path or use multiple gunicorn instance the "--lock-file" setting can be used to set the path of this file. fix #1259
This change add proper file locking to gunicorn. By default "gunicorn.lock" is created in the temporary directory when a unix socket is bound. In case someone want to fix the lock file path or use multiple gunicorn instance the "--lock-file" setting can be used to set the path of this file. fix #1259
This change add proper file locking to gunicorn. By default "gunicorn.lock" is created in the temporary directory when a unix socket is bound. In case someone want to fix the lock file path or use multiple gunicorn instance the "--lock-file" setting can be used to set the path of this file. fix #1259
This change add proper file locking to gunicorn. By default "gunicorn.lock" is created in the temporary directory when a unix socket is bound. In case someone want to fix the lock file path or use multiple gunicorn instance the "--lock-file" setting can be used to set the path of this file. fix #1259
This change add proper file locking to gunicorn. By default "gunicorn.lock" is created in the temporary directory when a unix socket is bound. In case someone want to fix the lock file path or use multiple gunicorn instance the "--lock-file" setting can be used to set the path of this file. fix benoitc#1259
Hi,
There is an exception that does not happen in 19.4.5 when trying to create a unix socket
In my application I am trying to create a two socket.
[('', 8081), '/Users/csanchez/var/dataserver.sock']
The first socket is created correctly and the second does not. The offending line is at 114. The reason may be because the fd is None
fd is None because the call to create the sockets never sets it.
/Users/csanchez/Documents/workspace/nti.dataserver-buildout/eggs/gunicorn-19.5.0-py2.7.egg/gunicorn/sock.py(227)create_sockets()
225 for i in range(5):
226 try:
--> 227 sock = sock_type(addr, conf, log)
...
In gunicorn-19.4.5 the call fcntl.lockf(self.sock, fcntl.LOCK_SH | fcntl.LOCK_NB) never happens
Thanks,
Carlos
trace.txt
The text was updated successfully, but these errors were encountered: