Pyverbs started out using Cython's __cinit__ method to initialize the underlying C objects. This is not recommended as the Python object may not be fully valid at this point. Move initialization to Python's __init__ instead. In addition, using __init__ allows us to control when and if the parent class's constructor is called. Signed-off-by: Noa Osherovich <noaos@xxxxxxxxxxxx> Reviewed-by: Edward Srouji <edwards@xxxxxxxxxxxx> --- pyverbs/addr.pyx | 23 ++++---- pyverbs/base.pyx | 4 +- pyverbs/cmid.pyx | 14 +++-- pyverbs/cq.pyx | 26 +++++---- pyverbs/device.pyx | 37 +++++++------ pyverbs/mr.pyx | 40 +++++++------- pyverbs/pd.pyx | 38 +++++++------- pyverbs/providers/mlx5/mlx5dv.pyx | 49 ++++++++++------- pyverbs/qp.pyx | 87 ++++++++++++++++--------------- pyverbs/srq.pyx | 20 ++++--- pyverbs/wr.pyx | 14 +++-- pyverbs/xrcd.pyx | 6 ++- 12 files changed, 200 insertions(+), 158 deletions(-) diff --git a/pyverbs/addr.pyx b/pyverbs/addr.pyx index 462a45bc7a4a..2ba611c26a89 100644 --- a/pyverbs/addr.pyx +++ b/pyverbs/addr.pyx @@ -18,7 +18,8 @@ cdef class GID(PyverbsObject): """ GID class represents ibv_gid. It enables user to query for GIDs values. """ - def __cinit__(self, val=None): + def __init__(self, val=None): + super().__init__() if val is not None: vals = gid_str_to_array(val) @@ -59,8 +60,8 @@ cdef class GRH(PyverbsObject): Represents ibv_grh struct. Used when creating or initializing an Address Handle from a Work Completion. """ - def __cinit__(self, GID sgid=None, GID dgid=None, version_tclass_flow=0, - paylen=0, next_hdr=0, hop_limit=1): + def __init__(self, GID sgid=None, GID dgid=None, version_tclass_flow=0, + paylen=0, next_hdr=0, hop_limit=1): """ Initializes a GRH object :param sgid: Source GID @@ -78,6 +79,7 @@ cdef class GRH(PyverbsObject): prior to being discarded :return: A GRH object """ + super().__init__() self.grh.dgid = dgid.gid self.grh.sgid = sgid.gid self.grh.version_tclass_flow = version_tclass_flow @@ -150,8 +152,8 @@ cdef class GlobalRoute(PyverbsObject): the values to be used in the GRH of the packets that will be sent using this Address Handle. """ - def __cinit__(self, GID dgid=None, flow_label=0, sgid_index=0, hop_limit=1, - traffic_class=0): + def __init__(self, GID dgid=None, flow_label=0, sgid_index=0, hop_limit=1, + traffic_class=0): """ Initializes a GlobalRoute object with given parameters. :param dgid: Destination GID @@ -167,6 +169,7 @@ cdef class GlobalRoute(PyverbsObject): delivery priority for routers :return: A GlobalRoute object """ + super().__init__() self.gr.dgid=dgid.gid self.gr.flow_label = flow_label self.gr.sgid_index = sgid_index @@ -222,8 +225,8 @@ cdef class GlobalRoute(PyverbsObject): cdef class AHAttr(PyverbsObject): """ Represents ibv_ah_attr struct """ - def __cinit__(self, dlid=0, sl=0, src_path_bits=0, static_rate=0, - is_global=0, port_num=1, GlobalRoute gr=None): + def __init__(self, dlid=0, sl=0, src_path_bits=0, static_rate=0, + is_global=0, port_num=1, GlobalRoute gr=None): """ Initializes an AHAttr object. :param dlid: Destination LID, a 16b unsigned integer @@ -242,6 +245,7 @@ cdef class AHAttr(PyverbsObject): is_global is non zero. :return: An AHAttr object """ + super().__init__() self.ah_attr.port_num = port_num self.ah_attr.sl = sl self.ah_attr.src_path_bits = src_path_bits @@ -363,7 +367,7 @@ cdef class AHAttr(PyverbsObject): cdef class AH(PyverbsCM): - def __cinit__(self, PD pd, **kwargs): + def __init__(self, PD pd, **kwargs): """ Initializes an AH object with the given values. Two creation methods are supported: @@ -371,7 +375,7 @@ cdef class AH(PyverbsCM): - Creation via a WC object (calls ibv_create_ah_from_wc) :param pd: PD object this AH belongs to :param kwargs: Arguments: - * *attr* (AHAttr) + * *attr* (AHAttr) An AHAttr object (represents ibv_ah_attr struct) * *wc* A WC object to use for AH initialization @@ -381,6 +385,7 @@ cdef class AH(PyverbsCM): Port number to be used for this AH (when using wc) :return: An AH object on success """ + super().__init__() if len(kwargs) == 1: # Create AH via ib_create_ah ah_attr = <AHAttr>kwargs['attr'] diff --git a/pyverbs/base.pyx b/pyverbs/base.pyx index d69516285ece..c5b16795ddb6 100644 --- a/pyverbs/base.pyx +++ b/pyverbs/base.pyx @@ -5,9 +5,11 @@ import logging from pyverbs.pyverbs_error import PyverbsRDMAError from libc.errno cimport errno + cpdef PyverbsRDMAErrno(str msg): return PyverbsRDMAError(msg, errno) + LOG_LEVEL=logging.INFO LOG_FORMAT='[%(levelname)s] %(asctime)s %(filename)s:%(lineno)s: %(message)s' logging.basicConfig(format=LOG_FORMAT, level=LOG_LEVEL, datefmt='%d %b %Y %H:%M:%S') @@ -38,7 +40,7 @@ cdef close_weakrefs(iterables): cdef class PyverbsObject(object): - def __cinit__(self): + def __init__(self): self.logger = logging.getLogger(self.__class__.__name__) def set_log_level(self, val): diff --git a/pyverbs/cmid.pyx b/pyverbs/cmid.pyx index c752feda8781..5e4401436105 100755 --- a/pyverbs/cmid.pyx +++ b/pyverbs/cmid.pyx @@ -13,8 +13,8 @@ from pyverbs.cq cimport WC cdef class ConnParam(PyverbsObject): - def __cinit__(self, resources=1, depth=1, flow_control=0, retry=5, - rnr_retry=5, srq=0, qp_num=0): + def __init__(self, resources=1, depth=1, flow_control=0, retry=5, + rnr_retry=5, srq=0, qp_num=0): """ Initialize a ConnParam object over an underlying rdma_conn_param C object which contains connection parameters. There are a few types of @@ -38,6 +38,7 @@ cdef class ConnParam(PyverbsObject): CMID. :return: ConnParam object """ + super().__init__() memset(&self.conn_param, 0, sizeof(cm.rdma_conn_param)) self.conn_param.responder_resources = resources self.conn_param.initiator_depth = depth @@ -60,7 +61,7 @@ cdef class ConnParam(PyverbsObject): cdef class AddrInfo(PyverbsObject): - def __cinit__(self, node=None, service=None, port_space=0, flags=0): + def __init__(self, node=None, service=None, port_space=0, flags=0): """ Initialize an AddrInfo object over an underlying rdma_addrinfo C object. :param node: Name, dotted-decimal IPv4 or IPv6 hex address to resolve. @@ -75,6 +76,7 @@ cdef class AddrInfo(PyverbsObject): cdef cm.rdma_addrinfo hints cdef cm.rdma_addrinfo *hints_ptr = NULL + super().__init__() if node is not None: node = node.encode('utf-8') address = <char*>node @@ -102,8 +104,8 @@ cdef class AddrInfo(PyverbsObject): cdef class CMID(PyverbsCM): - def __cinit__(self, object creator=None, QPInitAttr qp_init_attr=None, - PD pd=None): + def __init__(self, object creator=None, QPInitAttr qp_init_attr=None, + PD pd=None): """ Initialize a CMID object over an underlying rdma_cm_id C object. This is the main RDMA CM object which provides most of the rdmacm API. @@ -118,6 +120,8 @@ cdef class CMID(PyverbsCM): """ cdef v.ibv_qp_init_attr *init cdef v.ibv_pd *in_pd = NULL + + super().__init__() self.pd = None self.ctx = None if creator is None: diff --git a/pyverbs/cq.pyx b/pyverbs/cq.pyx index 1ea443fc6966..dda47207507f 100755 --- a/pyverbs/cq.pyx +++ b/pyverbs/cq.pyx @@ -17,12 +17,13 @@ cdef class CompChannel(PyverbsCM): for a CQ, the event is delivered via the completion channel attached to the CQ. """ - def __cinit__(self, Context context not None): + def __init__(self, Context context not None): """ Initializes a completion channel object on the given device. :param context: The device's context to use :return: A CompChannel object on success """ + super().__init__() self.cc = v.ibv_create_comp_channel(context.context) if self.cc == NULL: raise PyverbsRDMAErrno('Failed to create a completion channel') @@ -68,8 +69,8 @@ cdef class CQ(PyverbsCM): A Completion Queue is the notification mechanism for work request completions. A CQ can have 0 or more associated QPs. """ - def __cinit__(self, Context context not None, cqe, cq_context=None, - CompChannel channel=None, comp_vector=0): + def __init__(self, Context context not None, cqe, cq_context=None, + CompChannel channel=None, comp_vector=0): """ Initializes a CQ object with the given parameters. :param context: The device's context on which to open the CQ @@ -81,6 +82,7 @@ cdef class CQ(PyverbsCM): context's num_comp_vectors :return: The newly created CQ """ + super().__init__() if channel is not None: self.cq = v.ibv_create_cq(context.context, cqe, <void*>cq_context, channel.cc, comp_vector) @@ -173,8 +175,8 @@ cdef class CQ(PyverbsCM): cdef class CqInitAttrEx(PyverbsObject): - def __cinit__(self, cqe = 100, CompChannel channel = None, comp_vector = 0, - wc_flags = 0, comp_mask = 0, flags = 0): + def __init__(self, cqe = 100, CompChannel channel = None, comp_vector = 0, + wc_flags = 0, comp_mask = 0, flags = 0): """ Initializes a CqInitAttrEx object with the given parameters. :param cqe: CQ's capacity @@ -189,6 +191,7 @@ cdef class CqInitAttrEx(PyverbsObject): ibv_create_cq_attr_flags enum :return: """ + super().__init__() self.attr.cqe = cqe self.attr.cq_context = NULL self.attr.channel = NULL if channel is None else channel.cc @@ -255,8 +258,7 @@ cdef class CqInitAttrEx(PyverbsObject): cdef class CQEX(PyverbsCM): - def __cinit__(self, Context context not None, CqInitAttrEx init_attr, - **kwargs): + def __init__(self, Context context not None, CqInitAttrEx init_attr): """ Initializes a CQEX object on the given device's context with the given attributes. @@ -264,9 +266,10 @@ cdef class CQEX(PyverbsCM): :param init_attr: Initial attributes that describe the CQ :return: The newly created CQEX on success """ + super().__init__() self.qps = weakref.WeakSet() self.srqs = weakref.WeakSet() - if len(kwargs) > 0: + if self.cq != NULL: # Leave CQ initialization to the provider return if init_attr is None: @@ -380,9 +383,10 @@ cdef class CQEX(PyverbsCM): cdef class WC(PyverbsObject): - def __cinit__(self, wr_id=0, status=0, opcode=0, vendor_err=0, byte_len=0, - qp_num=0, src_qp=0, imm_data=0, wc_flags=0, pkey_index=0, - slid=0, sl=0, dlid_path_bits=0): + def __init__(self, wr_id=0, status=0, opcode=0, vendor_err=0, byte_len=0, + qp_num=0, src_qp=0, imm_data=0, wc_flags=0, pkey_index=0, + slid=0, sl=0, dlid_path_bits=0): + super().__init__() self.wc.wr_id = wr_id self.wc.status = status self.wc.opcode = opcode diff --git a/pyverbs/device.pyx b/pyverbs/device.pyx index 56d7540ceb6c..529c4e4597c9 100755 --- a/pyverbs/device.pyx +++ b/pyverbs/device.pyx @@ -70,7 +70,7 @@ cdef class Context(PyverbsCM): """ Context class represents the C ibv_context. """ - def __cinit__(self, **kwargs): + def __init__(self, **kwargs): """ Initializes a Context object. The function searches the IB devices list for a device with the name provided by the user. If such a device is @@ -79,19 +79,22 @@ cdef class Context(PyverbsCM): initiated pointer, hence all we have to do is assign this pointer to Context's object pointer. :param kwargs: Arguments: - * *name* (str) - The RDMA device's name - * *attr* (object) - Device-specific attributes, meaning that the device is to be - opened by the provider - * *cmid* (CMID) - A CMID object (represents rdma_cm_id struct) + * *name* + The device's name + * *attr* + Provider-specific attributes. If not None, it means that the + device will be opened by the provider and __init__ will return + after locating the requested device. + * *cmid* + A CMID object. If not None, it means that the device was already + opened by a CMID class, and only a pointer assignment is missing. :return: None """ cdef int count cdef v.ibv_device **dev_list cdef CMID cmid + super().__init__() self.pds = weakref.WeakSet() self.dms = weakref.WeakSet() self.ccs = weakref.WeakSet() @@ -99,19 +102,16 @@ cdef class Context(PyverbsCM): self.qps = weakref.WeakSet() self.xrcds = weakref.WeakSet() - dev_name = kwargs.get('name') + self.name = kwargs.get('name') provider_attr = kwargs.get('attr') cmid = kwargs.get('cmid') - if cmid is not None: self.context = cmid.id.verbs cmid.ctx = self return - elif dev_name is not None: - self.name = dev_name - else: - raise PyverbsUserError('Device name must be provided') + if self.name is None: + raise PyverbsUserError('Device name must be provided') dev_list = v.ibv_get_device_list(&count) if dev_list == NULL: raise PyverbsRDMAError('Failed to get devices list') @@ -393,7 +393,8 @@ cdef class DeviceAttr(PyverbsObject): cdef class QueryDeviceExInput(PyverbsObject): - def __cinit__(self, comp_mask): + def __init__(self, comp_mask): + super().__init__() self.ex_input.comp_mask = comp_mask @@ -583,7 +584,7 @@ cdef class DeviceAttrEx(PyverbsObject): cdef class AllocDmAttr(PyverbsObject): - def __cinit__(self, length, log_align_req = 0, comp_mask = 0): + def __init__(self, length, log_align_req = 0, comp_mask = 0): """ Creates an AllocDmAttr object with the given parameters. This object can than be used to create a DM object. @@ -592,6 +593,7 @@ cdef class AllocDmAttr(PyverbsObject): :param comp_mask: compatibility mask :return: An AllocDmAttr object """ + super().__init__() self.alloc_dm_attr.length = length self.alloc_dm_attr.log_align_req = log_align_req self.alloc_dm_attr.comp_mask = comp_mask @@ -622,13 +624,14 @@ cdef class AllocDmAttr(PyverbsObject): cdef class DM(PyverbsCM): - def __cinit__(self, Context context, AllocDmAttr dm_attr not None): + def __init__(self, Context context, AllocDmAttr dm_attr not None): """ Allocate a device (direct) memory. :param context: The context of the device on which to allocate memory :param dm_attr: Attributes that define the DM :return: A DM object on success """ + super().__init__() self.dm_mrs = weakref.WeakSet() device_attr = context.query_device_ex() if device_attr.max_dm_size <= 0: diff --git a/pyverbs/mr.pyx b/pyverbs/mr.pyx index 8747d9cb81f9..6b28c8173ef8 100644 --- a/pyverbs/mr.pyx +++ b/pyverbs/mr.pyx @@ -1,15 +1,17 @@ # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) # Copyright (c) 2019, Mellanox Technologies. All rights reserved. See COPYING file +import resource +import logging + from pyverbs.pyverbs_error import PyverbsRDMAError, PyverbsError from pyverbs.base import PyverbsRDMAErrno -from pyverbs.device cimport DM -from .pd cimport PD -import resource from posix.stdlib cimport posix_memalign -from libc.stdlib cimport free from libc.string cimport memcpy, memset from libc.stdint cimport uintptr_t +from pyverbs.device cimport DM +from libc.stdlib cimport free +from .pd cimport PD cdef class MR(PyverbsCM): @@ -17,7 +19,7 @@ cdef class MR(PyverbsCM): MR class represents ibv_mr. Buffer allocation in done in the c'tor. Freeing it is done in close(). """ - def __cinit__(self, PD pd not None, length, access, **kwargs): + def __init__(self, PD pd not None, length, access): """ Allocate a user-level buffer of length <length> and register a Memory Region of the given length and access flags. @@ -26,7 +28,8 @@ cdef class MR(PyverbsCM): :param access: Access flags, see ibv_access_flags enum :return: The newly created MR on success """ - if len(kwargs) != 0: + super().__init__() + if self.mr != NULL: return #We want to enable registering an MR of size 0 but this fails with a #buffer of size 0, so in this case lets increase the buffer @@ -107,13 +110,14 @@ cdef class MR(PyverbsCM): cdef class MW(PyverbsCM): - def __cinit__(self, PD pd not None, v.ibv_mw_type mw_type): + def __init__(self, PD pd not None, v.ibv_mw_type mw_type): """ Initializes a memory window object of the given type :param pd: A PD object :param mw_type: Type of of the memory window, see ibv_mw_type enum :return: """ + super().__init__() self.mw = NULL self.mw = v.ibv_alloc_mw(pd.pd, mw_type) if self.mw == NULL: @@ -144,29 +148,27 @@ cdef class MW(PyverbsCM): cdef class DMMR(MR): - def __cinit__(self, PD pd not None, length, access, **kwargs): + def __init__(self, PD pd not None, length, access, DM dm, offset): """ Initializes a DMMR (Device Memory Memory Region) of the given length and access flags using the given PD and DM objects. :param pd: A PD object :param length: Length in bytes :param access: Access flags, see ibv_access_flags enum - :param kwargs: see below + :param dm: A DM (device memory) object to be used for this DMMR + :param offset: Byte offset from the beginning of the allocated device + memory buffer :return: The newly create DMMR - - :keyword Arguments: - * *dm* (DM) - A DM (device memory) object to be used for this DMMR - * *offset* - Byte offset from the beginning of the allocated device memory - buffer """ - dm = <DM>kwargs['dm'] - offset = kwargs['offset'] - self.mr = v.ibv_reg_dm_mr(pd.pd, (<DM>dm).dm, offset, length, access) + # Initialize the logger here as the parent's __init__ is called after + # the DMMR is allocated. Allocation can fail, which will lead to + # exceptions thrown during object's teardown. + self.logger = logging.getLogger(self.__class__.__name__) + self.mr = v.ibv_reg_dm_mr(pd.pd, dm.dm, offset, length, access) if self.mr == NULL: raise PyverbsRDMAErrno('Failed to register a device MR. length: {len}, access flags: {flags}'. format(len=length, flags=access,)) + super().__init__(pd, length, access) self.pd = pd self.dm = dm pd.add_ref(self) diff --git a/pyverbs/pd.pyx b/pyverbs/pd.pyx index 8c17ffcba7e8..96d0078e3dbd 100755 --- a/pyverbs/pd.pyx +++ b/pyverbs/pd.pyx @@ -1,6 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) # Copyright (c) 2019, Mellanox Technologies. All rights reserved. import weakref +import logging from pyverbs.pyverbs_error import PyverbsUserError, PyverbsError from pyverbs.base import PyverbsRDMAErrno @@ -15,20 +16,16 @@ from pyverbs.qp cimport QP cdef class PD(PyverbsCM): - def __cinit__(self, object creator not None, **kwargs): + def __init__(self, object creator not None): """ Initializes a PD object. A reference for the creating Context is kept so that Python's GC will destroy the objects in the right order. - :param context: The Context object creating the PD - :param kwargs: Arguments: - * *attr* (object) - If provided PD will not be allocated, leaving the allocation to - be made by an inheriting class + :param creator: The Context/CMID object creating the PD """ + super().__init__() if issubclass(type(creator), Context): - # If there's a Parent Domain attribute skip PD allocation - # since this is done by the Parent Domain class - if not kwargs.get('attr'): + # Check if the ibv_pd* was initialized by an inheriting class + if self.pd == NULL: self.pd = v.ibv_alloc_pd((<Context>creator).context) if self.pd == NULL: raise PyverbsRDMAErrno('Failed to allocate PD') @@ -130,7 +127,7 @@ cdef void pd_free(v.ibv_pd *pd, void *pd_context, void *ptr, cdef class ParentDomainContext(PyverbsObject): - def __cinit__(self, PD pd, alloc_func, free_func): + def __init__(self, PD pd, alloc_func, free_func): """ Initializes ParentDomainContext object which is used as a pd_context. It contains the relevant fields in order to allow the user to write @@ -140,19 +137,21 @@ cdef class ParentDomainContext(PyverbsObject): :param alloc_func: Python alloc function :param free_func: Python free function """ + super().__init__() self.pd = pd self.p_alloc = alloc_func self.p_free = free_func cdef class ParentDomainInitAttr(PyverbsObject): - def __cinit__(self, PD pd not None, ParentDomainContext pd_context=None): + def __init__(self, PD pd not None, ParentDomainContext pd_context=None): """ Represents ibv_parent_domain_init_attr C struct :param pd: PD to initialize the ParentDomain with :param pd_context: ParentDomainContext object including the alloc and free Python callbacks """ + super().__init__() self.pd = pd self.init_attr.pd = <v.ibv_pd*>pd.pd if pd_context: @@ -171,25 +170,24 @@ cdef class ParentDomainInitAttr(PyverbsObject): cdef class ParentDomain(PD): - def __cinit__(self, Context context not None, **kwargs): + def __init__(self, Context context not None, ParentDomainInitAttr attr not None): """ Initializes ParentDomain object which represents a parent domain of ibv_pd C struct type :param context: Device context - :param kwargs: Arguments: - * *attr* (object) - Attribute of type ParentDomainInitAttr to initialize the - ParentDomain with + :param attr: Attribute of type ParentDomainInitAttr to initialize the + ParentDomain with """ - cdef ParentDomainInitAttr attr - attr = kwargs.get('attr') - if attr is None: - raise PyverbsUserError('ParentDomain must take attr') + # Initialize the logger here as the parent's __init__ is called after + # the PD is allocated. Allocation can fail, which will lead to exceptions + # thrown during object's teardown. + self.logger = logging.getLogger(self.__class__.__name__) (<PD>attr.pd).add_ref(self) self.protection_domain = attr.pd self.pd = v.ibv_alloc_parent_domain(context.context, &attr.init_attr) if self.pd == NULL: raise PyverbsRDMAErrno('Failed to allocate Parent Domain') + super().__init__(context) self.logger.debug('Allocated ParentDomain') def __dealloc__(self): diff --git a/pyverbs/providers/mlx5/mlx5dv.pyx b/pyverbs/providers/mlx5/mlx5dv.pyx index e4500567ba23..775c5504c2bb 100644 --- a/pyverbs/providers/mlx5/mlx5dv.pyx +++ b/pyverbs/providers/mlx5/mlx5dv.pyx @@ -1,6 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) # Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. See COPYING file +import logging + from pyverbs.pyverbs_error import PyverbsUserError cimport pyverbs.providers.mlx5.mlx5dv_enums as dve cimport pyverbs.providers.mlx5.libmlx5 as dv @@ -16,7 +18,8 @@ cdef class Mlx5DVContextAttr(PyverbsObject): Represent mlx5dv_context_attr struct. This class is used to open an mlx5 device. """ - def __cinit__(self, flags=0, comp_mask=0): + def __init__(self, flags=0, comp_mask=0): + super().__init__() self.attr.flags = flags self.attr.comp_mask = comp_mask @@ -44,22 +47,16 @@ cdef class Mlx5Context(Context): """ Represent mlx5 context, which extends Context. """ - def __cinit__(self, **kwargs): + def __init__(self, Mlx5DVContextAttr attr not None, name=''): """ Open an mlx5 device using the given attributes - :param kwargs: Arguments: - * *name* (str) - The RDMA device's name (used by parent class) - * *attr* (Mlx5DVContextAttr) - mlx5-specific device attributes + :param name: The RDMA device's name (used by parent class) + :param attr: mlx5-specific device attributes :return: None """ - cdef Mlx5DVContextAttr attr - attr = kwargs.get('attr') - if not attr or not isinstance(attr, Mlx5DVContextAttr): - raise PyverbsUserError('Missing provider attributes') if not dv.mlx5dv_is_supported(self.device): raise PyverbsUserError('This is not an MLX5 device') + super().__init__(name=name, attr=attr) self.context = dv.mlx5dv_open_device(self.device, &attr.attr) def query_mlx5_device(self, comp_mask=-1): @@ -187,7 +184,7 @@ cdef class Mlx5DVDCInitAttr(PyverbsObject): Represents mlx5dv_dc_init_attr struct, which defines initial attributes for DC QP creation. """ - def __cinit__(self, dc_type=dve.MLX5DV_DCTYPE_DCI, dct_access_key=0): + def __init__(self, dc_type=dve.MLX5DV_DCTYPE_DCI, dct_access_key=0): """ Initializes an Mlx5DVDCInitAttr object with the given DC type and DCT access key. @@ -195,6 +192,7 @@ cdef class Mlx5DVDCInitAttr(PyverbsObject): :param dct_access_key: Access key to be used by the DCT :return: An initializes object """ + super().__init__() self.attr.dc_type = dc_type self.attr.dct_access_key = dct_access_key @@ -223,8 +221,8 @@ cdef class Mlx5DVQPInitAttr(PyverbsObject): Represents mlx5dv_qp_init_attr struct, initial attributes used for mlx5 QP creation. """ - def __cinit__(self, comp_mask=0, create_flags=0, - Mlx5DVDCInitAttr dc_init_attr=None, send_ops_flags=0): + def __init__(self, comp_mask=0, create_flags=0, + Mlx5DVDCInitAttr dc_init_attr=None, send_ops_flags=0): """ Initializes an Mlx5DVQPInitAttr object with the given user data. :param comp_mask: A bitmask specifying which fields are valid @@ -233,6 +231,7 @@ cdef class Mlx5DVQPInitAttr(PyverbsObject): :param send_ops_flags: A bitwise OR of mlx5dv_qp_create_send_ops_flags :return: An initialized Mlx5DVQPInitAttr object """ + super().__init__() self.attr.comp_mask = comp_mask self.attr.create_flags = create_flags self.attr.send_ops_flags = send_ops_flags @@ -291,8 +290,8 @@ cdef class Mlx5DVQPInitAttr(PyverbsObject): cdef class Mlx5QP(QP): - def __cinit__(self, Mlx5Context context, QPInitAttrEx init_attr, - Mlx5DVQPInitAttr dv_init_attr): + def __init__(self, Mlx5Context context, QPInitAttrEx init_attr, + Mlx5DVQPInitAttr dv_init_attr): """ Initializes an mlx5 QP according to the user-provided data. :param context: mlx5 Context object @@ -301,6 +300,11 @@ cdef class Mlx5QP(QP): :return: An initialized Mlx5QP """ cdef PD pd + + # Initialize the logger here as the parent's __init__ is called after + # the QP is allocated. Allocation can fail, which will lead to exceptions + # thrown during object's teardown. + self.logger = logging.getLogger(self.__class__.__name__) self.dc_type = dv_init_attr.dc_type if dv_init_attr else 0 if init_attr.pd is not None: pd = <PD>init_attr.pd @@ -314,6 +318,7 @@ cdef class Mlx5QP(QP): raise PyverbsRDMAErrno('Failed to create MLX5 QP.\nQPInitAttrEx ' 'attributes:\n{}\nMLX5DVQPInitAttr:\n{}'. format(init_attr, dv_init_attr)) + super().__init__(context, init_attr) def _get_comp_mask(self, dst): masks = {dve.MLX5DV_DCTYPE_DCT: {'INIT': e.IBV_QP_PKEY_INDEX | @@ -338,7 +343,7 @@ cdef class Mlx5DVCQInitAttr(PyverbsObject): Represents mlx5dv_cq_init_attr struct, initial attributes used for mlx5 CQ creation. """ - def __cinit__(self, comp_mask=0, cqe_comp_res_format=0, flags=0, cqe_size=0): + def __init__(self, comp_mask=0, cqe_comp_res_format=0, flags=0, cqe_size=0): """ Initializes an Mlx5CQInitAttr object with zeroes as default values. :param comp_mask: Marks which of the following fields should be @@ -353,6 +358,7 @@ cdef class Mlx5DVCQInitAttr(PyverbsObject): Valid when MLX5DV_CQ_INIT_ATTR_MASK_CQE_SIZE is set. :return: None """ + super().__init__() self.attr.comp_mask = comp_mask self.attr.cqe_comp_res_format = cqe_comp_res_format self.attr.flags = flags @@ -413,8 +419,12 @@ cdef class Mlx5DVCQInitAttr(PyverbsObject): cdef class Mlx5CQ(CQEX): - def __cinit__(self, Mlx5Context context, CqInitAttrEx init_attr, - Mlx5DVCQInitAttr dv_init_attr): + def __init__(self, Mlx5Context context, CqInitAttrEx init_attr, + Mlx5DVCQInitAttr dv_init_attr): + # Initialize the logger here as the parent's __init__ is called after + # the CQ is allocated. Allocation can fail, which will lead to exceptions + # thrown during object's teardown. + self.logger = logging.getLogger(self.__class__.__name__) self.cq = \ dv.mlx5dv_create_cq(context.context, &init_attr.attr, &dv_init_attr.attr if dv_init_attr is not None @@ -426,6 +436,7 @@ cdef class Mlx5CQ(CQEX): self.ibv_cq = v.ibv_cq_ex_to_cq(self.cq) self.context = context context.add_ref(self) + super().__init__(context, init_attr) def __str__(self): print_format = '{:<22}: {:<20}\n' diff --git a/pyverbs/qp.pyx b/pyverbs/qp.pyx index 36698d2119e8..9d368b62022d 100755 --- a/pyverbs/qp.pyx +++ b/pyverbs/qp.pyx @@ -18,8 +18,8 @@ from libc.string cimport memcpy cdef class QPCap(PyverbsObject): - def __cinit__(self, max_send_wr=1, max_recv_wr=10, max_send_sge=1, - max_recv_sge=1, max_inline_data=0): + def __init__(self, max_send_wr=1, max_recv_wr=10, max_send_sge=1, + max_recv_sge=1, max_inline_data=0): """ Initializes a QPCap object with user-provided or default values. :param max_send_wr: max number of outstanding WRs in the SQ @@ -32,6 +32,7 @@ cdef class QPCap(PyverbsObject): inline to the SQ, otherwise 0 :return: """ + super().__init__() self.cap.max_send_wr = max_send_wr self.cap.max_recv_wr = max_recv_wr self.cap.max_send_sge = max_send_sge @@ -83,9 +84,9 @@ cdef class QPCap(PyverbsObject): cdef class QPInitAttr(PyverbsObject): - def __cinit__(self, qp_type=e.IBV_QPT_UD, qp_context=None, - PyverbsObject scq=None, PyverbsObject rcq=None, - SRQ srq=None, QPCap cap=None, sq_sig_all=1): + def __init__(self, qp_type=e.IBV_QPT_UD, qp_context=None, + PyverbsObject scq=None, PyverbsObject rcq=None, + SRQ srq=None, QPCap cap=None, sq_sig_all=1): """ Initializes a QpInitAttr object representing ibv_qp_init_attr struct. Note that SRQ object is not yet supported in pyverbs so can't be passed @@ -100,6 +101,7 @@ cdef class QPInitAttr(PyverbsObject): entry :return: A QpInitAttr object """ + super().__init__() _copy_caps(cap, self) self.attr.qp_context = <void*>qp_context if scq is not None: @@ -233,12 +235,12 @@ cdef class QPInitAttr(PyverbsObject): cdef class QPInitAttrEx(PyverbsObject): - def __cinit__(self, qp_type=e.IBV_QPT_UD, qp_context=None, - PyverbsObject scq=None, PyverbsObject rcq=None, - SRQ srq=None, QPCap cap=None, sq_sig_all=0, comp_mask=0, - PD pd=None, XRCD xrcd=None, create_flags=0, - max_tso_header=0, source_qpn=0, object hash_conf=None, - object ind_table=None): + def __init__(self, qp_type=e.IBV_QPT_UD, qp_context=None, + PyverbsObject scq=None, PyverbsObject rcq=None, + SRQ srq=None, QPCap cap=None, sq_sig_all=0, comp_mask=0, + PD pd=None, XRCD xrcd=None, create_flags=0, + max_tso_header=0, source_qpn=0, object hash_conf=None, + object ind_table=None): """ Initialize a QPInitAttrEx object with user-defined or default values. :param qp_type: QP type to be created @@ -261,6 +263,7 @@ cdef class QPInitAttrEx(PyverbsObject): :param ind_table: Not yet supported :return: An initialized QPInitAttrEx object """ + super().__init__() _copy_caps(cap, self) if scq is not None: if type(scq) is CQ: @@ -481,8 +484,8 @@ cdef class QPInitAttrEx(PyverbsObject): cdef class QPAttr(PyverbsObject): - def __cinit__(self, qp_state=e.IBV_QPS_INIT, cur_qp_state=e.IBV_QPS_RESET, - port_num=1, path_mtu=e.IBV_MTU_1024): + def __init__(self, qp_state=e.IBV_QPS_INIT, cur_qp_state=e.IBV_QPS_RESET, + port_num=1, path_mtu=e.IBV_MTU_1024): """ Initializes a QPQttr object which represents ibv_qp_attr structs. It can be used to modify a QP. @@ -491,6 +494,7 @@ cdef class QPAttr(PyverbsObject): :param cur_qp_state: Current QP state :return: An initialized QpAttr object """ + super().__init__() self.attr.qp_state = qp_state self.attr.cur_qp_state = cur_qp_state self.attr.port_num = port_num @@ -854,8 +858,8 @@ cdef class QPAttr(PyverbsObject): cdef class QP(PyverbsCM): - def __cinit__(self, object creator not None, object init_attr not None, - QPAttr qp_attr=None, **kwargs): + def __init__(self, object creator not None, object init_attr not None, + QPAttr qp_attr=None): """ Initializes a QP object and performs state transitions according to user request. @@ -875,39 +879,38 @@ cdef class QP(PyverbsCM): using Context). :param qp_attr: Optional QPAttr object. Will be used for QP state transitions after creation. - :param kwargs: Provider-specific QP creation attributes, meaning that - the QP will be created by the provider. :return: An initialized QP object """ cdef PD pd cdef Context ctx + super().__init__() self.update_cqs(init_attr) - if len(kwargs) > 0: - # Leave QP initialization to the provider - return - # In order to use cdef'd methods, a proper casting must be done, let's - # infer the type. - if issubclass(type(creator), Context): - self._create_qp_ex(creator, init_attr) - ctx = <Context>creator - self.context = ctx - ctx.add_ref(self) - if init_attr.pd is not None: - pd = <PD>init_attr.pd - pd.add_ref(self) - self.pd = pd - if init_attr.xrcd is not None: - xrcd = <XRCD>init_attr.xrcd - xrcd.add_ref(self) - self.xrcd = xrcd - else: - self._create_qp(creator, init_attr) - pd = <PD>creator - self.pd = pd - pd.add_ref(self) - self.context = None + # QP initialization was not done by the provider, we should do it here if self.qp == NULL: - raise PyverbsRDMAErrno('Failed to create QP') + # In order to use cdef'd methods, a proper casting must be done, + # let's infer the type. + if issubclass(type(creator), Context): + self._create_qp_ex(creator, init_attr) + ctx = <Context>creator + self.context = ctx + ctx.add_ref(self) + if init_attr.pd is not None: + pd = <PD>init_attr.pd + pd.add_ref(self) + self.pd = pd + if init_attr.xrcd is not None: + xrcd = <XRCD>init_attr.xrcd + xrcd.add_ref(self) + self.xrcd = xrcd + else: + self._create_qp(creator, init_attr) + pd = <PD>creator + self.pd = pd + pd.add_ref(self) + self.context = None + if self.qp == NULL: + raise PyverbsRDMAErrno('Failed to create QP') + if qp_attr is not None: funcs = {e.IBV_QPT_RC: self.to_init, e.IBV_QPT_UC: self.to_init, e.IBV_QPT_UD: self.to_rts, diff --git a/pyverbs/srq.pyx b/pyverbs/srq.pyx index a60aa5dcb0e5..7dc24d3849e4 100755 --- a/pyverbs/srq.pyx +++ b/pyverbs/srq.pyx @@ -10,7 +10,8 @@ from libc.string cimport memcpy cdef class SrqAttr(PyverbsObject): - def __cinit__(self, max_wr=100, max_sge=1, srq_limit=0): + def __init__(self, max_wr=100, max_sge=1, srq_limit=0): + super().__init__() self.attr.max_wr = max_wr self.attr.max_sge = max_sge self.attr.srq_limit = srq_limit @@ -38,11 +39,12 @@ cdef class SrqAttr(PyverbsObject): cdef class SrqInitAttr(PyverbsObject): - def __cinit__(self, SrqAttr attr = None): - if attr is not None: - self.attr.attr.max_wr = attr.max_wr - self.attr.attr.max_sge = attr.max_sge - self.attr.attr.srq_limit = attr.srq_limit + def __init__(self, SrqAttr attr = None): + super().__init__() + if attr is not None: + self.attr.attr.max_wr = attr.max_wr + self.attr.attr.max_sge = attr.max_sge + self.attr.attr.srq_limit = attr.srq_limit @property def max_wr(self): @@ -58,7 +60,8 @@ cdef class SrqInitAttr(PyverbsObject): cdef class SrqInitAttrEx(PyverbsObject): - def __cinit__(self, max_wr=100, max_sge=1, srq_limit=0): + def __init__(self, max_wr=100, max_sge=1, srq_limit=0): + super().__init__() self.attr.attr.max_wr = max_wr self.attr.attr.max_sge = max_sge self.attr.attr.srq_limit = srq_limit @@ -122,7 +125,8 @@ cdef class SrqInitAttrEx(PyverbsObject): cdef class SRQ(PyverbsCM): - def __cinit__(self, object creator not None, object attr not None): + def __init__(self, object creator not None, object attr not None): + super().__init__() self.srq = NULL self.cq = None if isinstance(creator, PD): diff --git a/pyverbs/wr.pyx b/pyverbs/wr.pyx index 8505c1cfddff..06186e9b0fd2 100644 --- a/pyverbs/wr.pyx +++ b/pyverbs/wr.pyx @@ -17,7 +17,7 @@ cdef class SGE(PyverbsCM): write can't be done using memcpy that relies on CPU-specific optimizations. A SGE has no way to tell which memory it is using. """ - def __cinit__(self, addr, length, lkey): + def __init__(self, addr, length, lkey): """ Initializes a SGE object. :param addr: The address to be used for read/write @@ -25,6 +25,7 @@ cdef class SGE(PyverbsCM): :param lkey: Local key of the used MR/DMMR :return: A SGE object """ + super().__init__() self.sge = <v.ibv_sge*>malloc(sizeof(v.ibv_sge)) if self.sge == NULL: raise PyverbsError('Failed to allocate an SGE') @@ -80,8 +81,8 @@ cdef class SGE(PyverbsCM): cdef class RecvWR(PyverbsCM): - def __cinit__(self, wr_id=0, num_sge=0, sg=None, - RecvWR next_wr=None): + def __init__(self, wr_id=0, num_sge=0, sg=None, + RecvWR next_wr=None): """ Initializes a RecvWR object. :param wr_id: A user-defined WR ID @@ -90,6 +91,7 @@ cdef class RecvWR(PyverbsCM): :param: next_wr: The next WR in the list :return: A RecvWR object """ + super().__init__() cdef v.ibv_sge *dst if num_sge < 1 or sg is None: raise PyverbsUserError('A WR needs at least one SGE') @@ -141,8 +143,8 @@ cdef class RecvWR(PyverbsCM): cdef class SendWR(PyverbsCM): - def __cinit__(self, wr_id=0, opcode=e.IBV_WR_SEND, num_sge=0, sg = None, - send_flags=e.IBV_SEND_SIGNALED, SendWR next_wr = None): + def __init__(self, wr_id=0, opcode=e.IBV_WR_SEND, num_sge=0, sg = None, + send_flags=e.IBV_SEND_SIGNALED, SendWR next_wr = None): """ Initialize a SendWR object with user-provided or default values. :param wr_id: A user-defined WR ID @@ -153,6 +155,8 @@ cdef class SendWR(PyverbsCM): :return: An initialized SendWR object """ cdef v.ibv_sge *dst + + super().__init__() if num_sge < 1 or sg is None: raise PyverbsUserError('A WR needs at least one SGE') self.send_wr.sg_list = <v.ibv_sge*>malloc(num_sge * sizeof(v.ibv_sge)) diff --git a/pyverbs/xrcd.pyx b/pyverbs/xrcd.pyx index 91303daf3bc0..774f60e60dda 100755 --- a/pyverbs/xrcd.pyx +++ b/pyverbs/xrcd.pyx @@ -12,7 +12,8 @@ from libc.errno cimport errno cdef class XRCDInitAttr(PyverbsObject): - def __cinit__(self, comp_mask, oflags, fd): + def __init__(self, comp_mask, oflags, fd): + super().__init__() self.attr.fd = fd self.attr.comp_mask = comp_mask self.attr.oflags = oflags @@ -40,12 +41,13 @@ cdef class XRCDInitAttr(PyverbsObject): cdef class XRCD(PyverbsCM): - def __cinit__(self, Context context not None, XRCDInitAttr init_attr not None): + def __init__(self, Context context not None, XRCDInitAttr init_attr not None): """ Initializes a XRCD object. :param context: The Context object creating the XRCD :return: The newly created XRCD on success """ + super().__init__() self.xrcd = v.ibv_open_xrcd(<v.ibv_context*> context.context, &init_attr.attr) if self.xrcd == NULL: -- 2.21.0