Am I crashing ctypes or libFLAC?
I have found a way to crash either libFLAC or ctypes through the use of threading, but how can this be possible? I don't remember ever reading that ctypes isn't thread-safe and libFLAC 1.2.1 is explicitly thread-safe.
Anyway, consider the program below. Towards the end there is a "for i in range()" loop. Setting the range to 1 works fine, but increasing it causes more and more SIGSEGV until the program never produces any output. Then, if you comment out the "from threading import ..." and instead enable the "from multiprocesseing ...", all the problems go away completely no matter how many instances you start concurrently.
Can anyone tell me what is going on here? Am I using ctypes incorrectly somehow?
Best regards / Klas
#! /usr/bin/python
import sys
import ctypes
import ctypes.util
# load the libFLAC .so
libflac = None
path = ctypes.util.find_library('FLAC')
if path:
libflac = ctypes.CDLL(path)
if not libflac or not libflac._name:
raise ImportError('failed to find libFLAC. Check your installation')
#### define cyptes prototypes for all library functions we need ####
SEARCH_FOR_METADATA = 0x0
END_OF_STREAM = 0x4
WRITE_STATUS_CONTINUE = 0x0
new = libflac.FLAC__stream_decoder_new
new.restype = ctypes.c_void_p
new.params = []
delete = libflac.FLAC__stream_decoder_delete
delete.restype = None
delete.params = [ctypes.c_void_p]
init_file = libflac.FLAC__stream_decoder_init_file
init_file.restype = ctypes.c_int
init_file.params = [
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p
]
write_callback_type = ctypes.CFUNCTYPE(
ctypes.c_int,
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p
)
error_callback_type = ctypes.CFUNCTYPE(
None,
ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p
)
def write_callback(decoder, frame, buf, user):
print 'write_callback()'
return WRITE_STATUS_CONTINUE
def error_callback(decoder, status, user):
print 'error_callback()'
#### end of ctypes prototypes ####
class FlacDecoder(object):
decoder = None
path = None
def __del__(self):
delete(self.decoder)
pass
def __init__(self, path):
self.decoder = new()
self.path = path
# IMPORTANT: the callbacks must be saved somewhere to prevent the
# garbage collector from smoking them (which leads to segfaults if
# the calls are ever made)
self.cb1 = write_callback_type(write_callback)
self.cb3 = error_callback_type(error_callback)
state = init_file(
self.decoder, self.path, self.cb1, None, self.cb3, self.path
)
if state != SEARCH_FOR_METADATA:
raise Exception('decoder_init_file() failed')
path = sys.argv[1].encode('utf-8')
def target(cursor):
while True:
dec = FlacDecoder(path)
sys.stdout.write(cursor)
开发者_运维技巧
from threading import Thread
#from multiprocessing import Process as Thread
for i in range(2):
t = Thread(target=target, args=(str(i),))
t.daemon = True # so the program can quite without joining all the threads
t.start()
while True:
try:
pass
except KeyboardInterrupt:
break
I am running this on a Debian Squeeze system:
$ uname -a
Linux tor 2.6.32-trunk-amd64 #1 SMP Sun Jan 10 22:40:40 UTC 2010 x86_64 GNU/Linux
Version of Python:
$ dpkg -s python2.6
Package: python2.6
Status: install ok installed
Priority: standard
Section: python
Installed-Size: 9240
Maintainer: Matthias Klose <doko@debian.org>
Architecture: amd64
Version: 2.6.6-10
Provides: python2.6-celementtree, python2.6-cjkcodecs, python2.6-ctypes, python2.6-elementtree, python2.6-wsgiref
Depends: python2.6-minimal (= 2.6.6-10), mime-support, libbz2-1.0, libc6 (>= 2.3), libdb4.8, libexpat1 (>= 1.95.8), libncursesw5 (>= 5.6+20070908), libreadline6 (>= 6.0), libsqlite3-0 (>= 3.5.9)
Version of libFLAC:
$ dpkg -s libflac8
Package: libflac8
Status: install ok installed
Priority: optional
Section: libs
Installed-Size: 360
Maintainer: Debian Multimedia Maintainers <pkg-multimedia-maintainers@lists.alioth.debian.org>
Architecture: amd64
Source: flac
Version: 1.2.1-4
Depends: libc6 (>= 2.2.5), libogg0 (>= 1.0rc3)
精彩评论