Re: [Pythonmac-SIG] urllib2.urlopen fails in a forked daemon with a CoreFoundation error

2009-03-16 Thread Jarkko Laiho
On Sun, Mar 15, 2009 at 9:13 PM, Bill Janssen jans...@parc.com wrote:
 You need to do an exec after doing a fork.  /usr/bin/python on OS X
 is a framework build, and some (most?) of the OS X frameworks just
 don't work after doing a fork.  You have to restart with an exec.

All right, but how is this done?

I'll refer to the code I'm using:

http://code.activestate.com/recipes/278731/

The first fork happens at line 55, and the second at line 103. As
said, I really don't understand this fork/exec business so I don't
know what I should do. Which of the many exec* functions in the os
module should I run, and with what parameters? The forking without
exec already does everything I need it to do daemonizing-wise (except
satisfy CoreFoundation), so what am I trying to accomplish? What does
CF actually require me to do, and does it mess up or require further
changes in the forking methodology I'm using?

- Jarkko L.
___
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig


Re: [Pythonmac-SIG] urllib2.urlopen fails in a forked daemon with a CoreFoundation error

2009-03-16 Thread Bill Janssen
Jarkko Laiho jarkko.la...@iki.fi wrote:

 So ultimately the question is: how should the forking code in the
 recipe be modified, so that it satisfies the requirements of OS X?
 What does an actual, concrete exec() call look like in this case, and
 at what point in the code should it occur?

I don't know -- you didn't post your entire program.  Read the Wikipedia
page and follow the refs.  Here's an example:

def daemon ():

try:
pid = os.fork()
if pid  0:
sys.exit(0) # parent
except OSError, e:
msg = fork #1 failed: (%d) %s\n % (e.errno, e.strerror)
sys.stderr.write(msg)
sys.exit(1)

os.umask(0)
# now create a new session
os.setsid()
# and fork into the new session

try:
pid = os.fork()
if pid  0:
sys.exit(0) # session leader exits here
except OSError, e:
msg = fork #2 failed: (%d) %s\n % (e.errno, e.strerror)
sys.stderr.write(msg)
sys.exit(1)

# here you could make any changes you need to the env, like setting 
PYTHONPATH
env = os.environ.copy()
# figure out how to invoke the actual program
args = [sys.executable, -c,
import mycode; +
mycode.realmain()
]
os.execve(sys.executable, args, env)

   
def realmain():

start_server()

# the real main...
# this is basically just an event-handling loop

while True:
try:
asyncore.loop()
except (KeyboardInterrupt, SystemExit), x:
note(4, Exited from main loop due to exception:\n%s, 
''.join(traceback.format_exception(*sys.exc_info(
raise
except:
note(0, Exited from main loop due to exception:\n%s, 
''.join(traceback.format_exception(*sys.exc_info(


if __name__ == __main__ and (not sys.platform.lower().startswith(win)):
daemon()
___
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig


Re: [Pythonmac-SIG] urllib2.urlopen fails in a forked daemon with a CoreFoundation error

2009-03-16 Thread Jarkko Laiho
 What does an actual, concrete exec() call look like in this case, and
 at what point in the code should it occur?
 I don't know -- you didn't post your entire program.  Read the Wikipedia
 page and follow the refs.

I did and understood just about none of it. Way over my head. But:

 Here's an example:
 [...]
    # figure out how to invoke the actual program
    args = [sys.executable, -c,
            import mycode; +
            mycode.realmain()
            ]
    os.execve(sys.executable, args, env)
[...]

There's a technique I didn't know about. I didn't think there was any
way of making an exec() call fit the existing code, but that might
just do the trick.

I'm pretty sure I can work with that. Thanks for your patient advice!

- Jarkko L.
___
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig


Re: [Pythonmac-SIG] urllib2.urlopen fails in a forked daemon with a CoreFoundation error

2009-03-15 Thread Bill Janssen
You need to do an exec after doing a fork.  /usr/bin/python on OS X
is a framework build, and some (most?) of the OS X frameworks just
don't work after doing a fork.  You have to restart with an exec.

It's hard to say just what is using CF; I see you're importing some
external packages (json doesn't come with 2.5.1 on OS X), so it might
be one of them, instead of urllib2.  But it's probably the urllib
module, which uses CF to call into the SystemConfiguration system on the
Mac to look up proxies and such.  It would make sense that the error
is triggered just when you call urlopen().

Bill
___
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig


[Pythonmac-SIG] urllib2.urlopen fails in a forked daemon with a CoreFoundation error

2009-03-14 Thread Jarkko Laiho
Hi all,

I'm writing a simple daemon to test out a web application that
receives messages via HTTP, using urllib2 for the HTTP connections.
The program daemonizes nicely and sends the messages just fine, but
when it's sending the first message (which takes place 2-12 seconds
after starting the program, since the send interval is randomized),
the terminal I started the program from prints out:

The process has forked and you cannot use this CoreFoundation
functionality safely. You MUST exec().
Break on 
__THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__()
to debug.

...repeating it several dozen times.

The execution of the program seems to run normally regardless, at
least the messages arrive to the HTTP server just fine.

I'm running OS X Leopard 10.5.6, the system default Python 2.5.1, and
using this daemonizing code:
http://code.activestate.com/recipes/278731/


The actual offending bit in my own code is inside __main__, and occurs
in the main loop of the program, right after the daemonization has
taken place:

[...code...]

while True:
time.sleep(int(random.random() * 10 + 2))
params = urllib.urlencode({'json':
json.dumps({'msg': random_items(phrases)[0][1],
'chan': '07101237-20ad-4229-b663-0c3dd46b8706'}
)
})
req = urllib2.Request('http://localhost:8000/json/new_msg/',
params, headers)
try:
fd = urllib2.urlopen(req) # THIS PRODUCES THE ERROR
response = fd.read()
except urllib2.HTTPError, e:
sys.exit(1)

[...more code...]

I commented and gradually uncommented bunches of code until the error
disappeared, and I narrowed it down to the urllib2.urlopen call: if it
(and the next row that depends on it) are commented out, the error
doesn't appear.

Googling the error revealed this Leopard release notes document from Apple:

http://developer.apple.com/releasenotes/CoreFoundation/CoreFoundation.html

Relevant quote:

CoreFoundation and fork()

Due to the behavior of fork(), CoreFoundation cannot be used on the
child-side of fork(). If you fork(), you must follow that with an
exec*() call of some sort, and you should not use CoreFoundation APIs
within the child, before the exec*(). The applies to all higher-level
APIs which use CoreFoundation, and since you cannot know what those
higher-level APIs are doing, and whether they are using CoreFoundation
APIs, you should not use any higher-level APIs either. This includes
use of the daemon() function.

Additionally, per POSIX, only async-cancel-safe functions are safe to
use on the child side of fork(), so even use of lower-level
libSystem/BSD/UNIX APIs should be kept to a minimum, and ideally to
only async-cancel-safe functions.

This has always been true, and there have been notes made of this on
various Cocoa developer mailling lists in the past. But CoreFoundation
is taking some stronger measures now to enforce this limitation, so
we thought it would be worthwhile to add a release note to call this
out as well. A message is written to stderr when something uses API
which is definitely known not to be safe in CoreFoundation after
fork(). If file descriptor 2 has been closed, however, you will get no
message or notice, which is too bad. We tried to make processes
terminate in a very recognizable way, and did for a while and that was
very handy, but backwards binary compatibility prevented us from doing
so.


Now, I know nothing about CoreFoundation and just about nothing about
the Unix side of things (fork/exec etc.), but it appears that
urllib2.urlopen is somehow dependent on some CoreFoundation code and
thus doesn't play well with fork(). If one of the os.exec* functions
need to be used, like the release notes suggest, I have no idea how
and where.

Is this a bug that should be reported either to Apple or to the Python
people, or do I simply need a different type of forking semantic in a
Leopard system?

Any advice will be much appreciated.

- Jarkko Laiho
___
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig