Home  >  Article  >  Backend Development  >  The return value when Python calls C SDK does not meet expectations and the solution to Segmentation fault

The return value when Python calls C SDK does not meet expectations and the solution to Segmentation fault

高洛峰
高洛峰Original
2017-03-20 11:04:101868browse

1. The sdk return value is not int type

1.1 LoginFunctionCall

def login(ip, port, username, password, device_info, error_code):
"""
LLONG CLIENT_Login(
char *pchDVRIP, WORD wDVRPort,
char *pchUserName, char *pchPassword,
LPNET_DEVICEINFO lpDeviceInfo, int *error = 0);
:param ip:
:param port:
:param username:
:param password:
:param device_info:
:param error_code:
:return: LLONG
"""
ip_buffer = c_buffer(ip)
# ip_buffer.encode('utf8')
# user_id = c_longlong(0)
user_id = SDK._dll.CLIENT_Login( byref(ip_buffer), port, username, password, byref(device_info), byref(error_code))
return user_id # c_longlong(user_id).value

1.2 Invalid ID

User ID is used as a handle and is passed into other SDK functions. An error is reported and the handle is invalid. Check for negative values. Therefore, it is suspected that there is a type mismatch

Python调用C的SDK出现返回值不符合预期以及Segmentation fault的解决方法

1.3 Set the return type

1.3.1 Error cause

Check online I checked it and read the documentation. When calling the C sdk in python, the default return type is int. According to the function definition of the login C version, the return type is LLONG

15.17. 1.8. Return types

By default functions are assumed to return the C int type. Other return types can be specified by setting the restype attribute of the function object.

Here is a more advanced example, it uses the strchr function, which expects a string pointer and a char, and returns a pointer to a string:

>>> strchr = libc.strchr
>>> strchr("abcdef", ord("d"))  
8059983
>>> strchr.restype = c_char_p   # c_char_p is a pointer to a string
>>> strchr("abcdef", ord("d"))
'def'
>>> print strchr("abcdef", ord("x"))
None
>>>

1.3.2 Modify

Set the return value of sdk function to c_longlong, the problem is solved

SDK._dll.CLIENT_Login. restype = c_longlong

2, Callback functionSegmentation fault is likely to occur in this scenario

After searching online, there are generally two possibilities: The memory is out of bounds or illegal to read or write; another is that the function call stack is too deep.

2.1 Read-write lock

The code itself adds Condition read-write lock, and buf is also allocated when writing. After repeated debugging, it should not be the problem here. Printing the log shows that it has nothing to do with read and write operations.

Write

index = userdata  # c_uint(userdata).value
_buf_cond.acquire()
# time.sleep(0.2)

# 复制图片到内存
# _pic_buf.buf = pBuf  c_char 和 c_byte转换
try:
    temp = [pBuf[i] for i in xrange(0, RevLen)]
    _buf_list[index].buf = struct.pack('%db' % RevLen, *temp)
    # 序列号
    _buf_list[index].sn = c_ulong(CmdSerial).value
    _buf_list[index].id = index
    _buf_list[index].size = c_uint(RevLen).value
    _buf_list[index].ext = 'jpeg'  # encode_dict.get(EncodeType, 'jpeg')
except Exception, e:
    logger.error('截图缓存发生异常:%s' % str(e))
finally:
    _buf_cond.notify()
    _buf_cond.release()
_buf_cond.acquire()
_buf_cond.wait(timeout=15.0)
# 等待200ms再访问数据
# time.sleep(0.2)
if _buf_list[self.index].sn == snap.CmdSerial and _buf_list[self.index].id == self.index:
    self.save_picture(_buf_list[self.index].buf, _buf_list[self.index].ext)
    self.info('针对通道%d截图成功,IP:%s,Port:%s' % (channel, self.ip, self.port))
    pass
_buf_cond.release()

2.2 Reduce stack call level

After introducing this sdk, a callback function is used. Therefore, the callback function definition level is reduced.

2.2.1 Before modification

Pass in the function to the base class, and instantiate the function CFUNCTYPE in the base class

Defined in the base class

self.callback = CFUNCTYPE(c_void_p, c_longlong, POINTER(c_byte), c_uint, c_uint, c_ulong, c_ulonglong)
def set_callback(self, save_after_recv_pic, index):
    self.dll.CLIENT_SetSnapRevCallBack(self._callback(save_after_recv_pic), index)
子类中定义,_save_after_recv_pic也在子类中定义为staticmethod
def _set_callback(self):
    try:
        if 0 <= self.index < _buf_size:
            self.set_callback(self._save_after_recv_pic, self.index)   # 函数调用层次太深,经常报segmentation fault
            return True
        else:
            self.error('设置截图保存回调函数的userdata参数错误:%d' % self.index)
            return False
    except Exception, e:
        self.error('设置截图保存回调函数失败,%s' % str(e))
        return False
 

2.2.2 Problem solved after modification

Directly instantiate the callback function in the subclass

self.capture_callback = self.callback(self._save_after_recv_pic)
子类中直接注册回调函数
def _set_callback(self):
    try:
        if 0 <= self.index < _buf_size:
            self.dll.CLIENT_SetSnapRevCallBack(self.capture_callback, self.index)
            # self.set_callback(self._save_after_recv_pic, self.index)   # 函数调用层次太深,经常报segmentation fault
            return True
        else:
            self.error('设置截图保存回调函数的userdata参数错误:%d' % self.index)
            return False
    except Exception, e:
        self.error('设置截图保存回调函数失败,%s' % str(e))
        return False

The above is the detailed content of The return value when Python calls C SDK does not meet expectations and the solution to Segmentation fault. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn