From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1A6CFA034F; Mon, 29 Mar 2021 05:14:42 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 87C8B4069B; Mon, 29 Mar 2021 05:14:41 +0200 (CEST) Received: from EUR02-VE1-obe.outbound.protection.outlook.com (mail-eopbgr20066.outbound.protection.outlook.com [40.107.2.66]) by mails.dpdk.org (Postfix) with ESMTP id 05E4240042 for ; Mon, 29 Mar 2021 05:14:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=QTpaxQpDcOuTvrtqDXZNORUM7G6BAvrcRFkRZEuCWyI=; b=NbJLmmbtmqOn3OHMYP5ZPJPSYJORWYaGbDQAIlMlov0oKxnSBmACJZpXiLdYq/+u7yiVrdI8vaZ4VmHH+l6CYGSzRue5EO3K5qPBNX7wJVZPDDyG9i6DO40gK9I/nL/yCpo89A3GmEIbJUQJSooOOznoE3C9y6lI7fRUliqz9os= Received: from DB7PR02CA0028.eurprd02.prod.outlook.com (2603:10a6:10:52::41) by VI1PR08MB4303.eurprd08.prod.outlook.com (2603:10a6:803:f6::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.25; Mon, 29 Mar 2021 03:14:38 +0000 Received: from DB5EUR03FT032.eop-EUR03.prod.protection.outlook.com (2603:10a6:10:52:cafe::ed) by DB7PR02CA0028.outlook.office365.com (2603:10a6:10:52::41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Mon, 29 Mar 2021 03:14:38 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dpdk.org; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dpdk.org; dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by DB5EUR03FT032.mail.protection.outlook.com (10.152.20.162) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.25 via Frontend Transport; Mon, 29 Mar 2021 03:14:37 +0000 Received: ("Tessian outbound 7fa7bf2c820c:v89"); Mon, 29 Mar 2021 03:14:37 +0000 X-CR-MTA-TID: 64aa7808 Received: from c0f574e36578.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 3DEF6FB1-9062-4551-A664-D9B657879913.1; Mon, 29 Mar 2021 03:14:32 +0000 Received: from EUR04-DB3-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id c0f574e36578.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Mon, 29 Mar 2021 03:14:32 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=CpvaEiHg/IsCS1HHA7Gaj/MFS77xqGheWUUF8s6fFGRD1RhGx+OT4HFp8+qcPP9VqH5TVELENZLJRpmylMPAD8ISTNrFmnHGzn9LVqte+O2N2A2mXSrnsZ/nnoR4FcRmnxptsM4uFd5XT0LZd/ssp4mbfB1xhoE0FjNxSin4FdaSCrVR7rk2fI5eQiE2+KSrHmpKQSJ8ljks0pcnQdoncSlh9JJNMaGDXrGh3/It2Ex8UNxuRSShbbToeRfFGz4nKjlGwzpbISA5NoHI8pAzgv1+BpW08dBq/vnntHOcHurbnKCTO12z52U2447DjVqdtkpoi0Lc5DBY4KxMszHD4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=QTpaxQpDcOuTvrtqDXZNORUM7G6BAvrcRFkRZEuCWyI=; b=ft9TjsnunxCPmnbAxlkCLQtTvoKmEdcmZiKc9A0WUZUJLJD80YlDVZWw9uIdJLwp+fwNG/lDdHLxoQlC4i8gHEeXn92EH4h52ukVQTgJ+wSV8OsJxqAK71s0rDnMSVEtfyl7aSdcHVMdM8MxBR2ps+KiJ2D0ayAFOI2gHNn9W04BMWC7cOhRVArEBVUx079NXG/W15CQ69SNW8BipWOGjjL9X0MfOQqENsYnt9xBYdTO+AJR6b9tqUQelWQWuXdmOTe8s0533ghCVY9arktL6KicAec/LFsbDv2BM47N+JMT+nWksqpskdmEBeFFZ98JkSk0rvR//yfA+D2lpnFwSg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=QTpaxQpDcOuTvrtqDXZNORUM7G6BAvrcRFkRZEuCWyI=; b=NbJLmmbtmqOn3OHMYP5ZPJPSYJORWYaGbDQAIlMlov0oKxnSBmACJZpXiLdYq/+u7yiVrdI8vaZ4VmHH+l6CYGSzRue5EO3K5qPBNX7wJVZPDDyG9i6DO40gK9I/nL/yCpo89A3GmEIbJUQJSooOOznoE3C9y6lI7fRUliqz9os= Received: from DBAPR08MB5814.eurprd08.prod.outlook.com (2603:10a6:10:1b1::6) by DB7PR08MB2953.eurprd08.prod.outlook.com (2603:10a6:5:1b::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.25; Mon, 29 Mar 2021 03:14:29 +0000 Received: from DBAPR08MB5814.eurprd08.prod.outlook.com ([fe80::2994:a01e:2de:f94e]) by DBAPR08MB5814.eurprd08.prod.outlook.com ([fe80::2994:a01e:2de:f94e%7]) with mapi id 15.20.3977.033; Mon, 29 Mar 2021 03:14:29 +0000 From: Honnappa Nagarahalli To: Stephen Hemminger , "dev@dpdk.org" CC: Stephen Hemminger , nd , Honnappa Nagarahalli , nd Thread-Topic: [PATCH v3] pflock: implementation of phase-fair reader writer locks Thread-Index: AQHXEGI/IcKJ0QLg6kiRYsPAmdlFQaqZ1Dsw Date: Mon, 29 Mar 2021 03:14:29 +0000 Message-ID: References: <20210212013838.312623-1-sthemmin@microsoft.com> <20210303191945.94617-1-sthemmin@microsoft.com> In-Reply-To: <20210303191945.94617-1-sthemmin@microsoft.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ts-tracking-id: 0E8606B98B1AEF419EDEB589FC9E3CBC.0 x-checkrecipientchecked: true Authentication-Results-Original: networkplumber.org; dkim=none (message not signed) header.d=none;networkplumber.org; dmarc=none action=none header.from=arm.com; x-originating-ip: [70.113.13.105] x-ms-publictraffictype: Email X-MS-Office365-Filtering-HT: Tenant X-MS-Office365-Filtering-Correlation-Id: 858be6d0-35ed-475e-46bb-08d8f260c920 x-ms-traffictypediagnostic: DB7PR08MB2953:|VI1PR08MB4303: x-ms-exchange-transport-forked: True X-Microsoft-Antispam-PRVS: x-checkrecipientrouted: true nodisclaimer: true x-ms-oob-tlc-oobclassifiers: OLM:1303;OLM:1303; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: Ps8gGGFJX5u2cJronCMJJRJcLMNUNpaviMresLUUb9NwK2jmpAxi8L5Zzvk6EcnPl72vD9Y7DWIJIB1L+BeAqcNSTNLekNN1iyEM6BgmMCvqPXpTTDXRMmGOISCWOhKhY/0EmfNKEKEtLHLccOvh5KeGG8c5i3Ehr6tguWaJ2Zt15ZTJhB3nN7bBACWiGO+HlRNHvSct1Hr6Vo9bzxW6InIQRNhZkTEOdEe7QNpVP6jg8Sz8E5W0nTCcAm3N1kEWtX9yyT+wE+V0GYfyWFrr2EFqIJTgCm6U4jftVIKYOJfroZIebzPVYh1KUg0nlYlque+s8IdwOnKHavIQaHfLXnYyKcm/OMXjQ0o0OCwW1Mf2aO0u0cspEJX9XWymMMDuaNTFBzXKJfGJRRXiofS0Xy0w22ZU1xAxPNv+C4pHYwRs56tCNg1zZBsYs/tVdItLVwWVRAcpaz+QkfvQFniuEkBgLPkkPrboZ14Cq2lAdvCUsegBs77k63b59DDR0edDPNWDrX/0Ihqu/vu/I3MXR9XHU0WZ/ufLXNl+32jofvRkEqJ5/OVZ8Ft3HIa6qJOu2/CyQf+cIPfWHQN48CwcTkzTd/GMl5OcFDHoAC+v9PRWbmdGL3yhy7Hzb3Vn3RQsRCL8gxmS5cs0GbVzW7iv0sVQOiEGYJnzFTGyqBlrcIQvrXLb7Y9XxdI94NZhekewHRCwDvCKO9QZMX2O1K1sKNuZAbHVP5kBNT350i1/tR49tMd5WmOQ0FHL80MqRibq X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:DBAPR08MB5814.eurprd08.prod.outlook.com; PTR:; CAT:NONE; SFS:(4636009)(346002)(136003)(39860400002)(396003)(376002)(366004)(4326008)(8676002)(54906003)(30864003)(2906002)(316002)(71200400001)(86362001)(5660300002)(26005)(7696005)(6506007)(186003)(33656002)(966005)(478600001)(45080400002)(76116006)(66446008)(66476007)(64756008)(66556008)(66946007)(52536014)(55016002)(9686003)(83380400001)(8936002)(38100700001)(110136005)(579004)(559001); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata: =?us-ascii?Q?FGH3hW1/WEOAWKzeTNOmfGfZYJ2Yyp9d/OttMoAeYHdMKpTtMZGK5+oN10XJ?= =?us-ascii?Q?JcOLEN8w+SaA8d9Mr4WrFV2234N929Ey7fX4VOWFQv/QKl74MAHSKDNLrx7e?= =?us-ascii?Q?8imvm+xP9LntZSwJrBPlBC0RtGakwrec9FEUWwJeTI3mXFvfvQqmnQUxHn1Q?= =?us-ascii?Q?jA2kuQxCLRFckGMtPeUCFPLFUHvxuduuYI5Uc3sZLEdmGwa96jzqIwqEEFRg?= =?us-ascii?Q?6Qc/Y1oSTMSka890//5IKhemY4HyzwmtO0lZAX0GWlrzyfEOvpArQxKqojkW?= =?us-ascii?Q?EaHPDiELWktXmXdsz8eZtEClhFXAp+Lf78dW+PAxfyQo/ZcsHNcXb+HGWyrb?= =?us-ascii?Q?pFhkqui/Zn/h254eaC5LmzfJMhvKyfA2E/H2cM3yOH4v6LOD+/W0AeoIOR/o?= =?us-ascii?Q?RkyKRnfGoi1TEQFtcQ7LKUk3IwdWqQH4+w++NknYnv/muIU1dkXAb/woUjYh?= =?us-ascii?Q?4+04D9SUK9GdykclsBQA/I842duSQzOQv+gsdd6BxQ4ZZe+kwoaNdAE3UDgI?= =?us-ascii?Q?F9OKFDl0aGWnHhFeqYURv1WUrmNL1EpbOg9laqj9YNAWIbjOegMRg+TfSlyU?= =?us-ascii?Q?yBkTNYfGWB6tgj0Np7VdsJkxb/t525f97pXzaxMMpENCqlMsxVMvMFwWnZ57?= =?us-ascii?Q?BVROrGJdGxrsHgdOB7iCU3gTq2B8LfRaOBItMhaBtmcuwSpHlklZTXhxrbp8?= =?us-ascii?Q?81xyqFG4gyKkDzFWbrZZZA6/6Bpal5AWJXM+1BHMBMAbjl0mVISwfU1HHWxT?= =?us-ascii?Q?Sih6bAWqQChx26lMeBFsz4pQXZMhniifZEyhBfmFj5wIQnC7V1t1eDZpw/ge?= =?us-ascii?Q?x2aY/oefRe0YkPoxJ0EroJF4g6Mmp3EgX2xGtGSEd7iRBM1TX08tekSgKgYt?= =?us-ascii?Q?R25a3B5q7X+nIIamVTZXcZA7MvAkDi78/q+uHIK65PSGC7FD3DcwUKTSF7hq?= =?us-ascii?Q?IL33wK3m+BwaHMIV5NFKh3cQG1eE3NZvTbqN2rsAGWE9mENd0e+WL/JgKGxe?= =?us-ascii?Q?GtHqEwImsr0P5PblMANQRCAdEyLvcIlLoW3vOdjyLwUiOJawBEhD6Z5xfkyd?= =?us-ascii?Q?9/La96xZD9LwjLnjxr+BmS9rV06CgMRWAH3XhRZWvOlNlOmjYKLIzqs+W0LS?= =?us-ascii?Q?TGVA83gOhR7Uq6cSIUitlaDqfyuZ7UTgW3iaLHhFzzBFVQURI+GhJIKca+7c?= =?us-ascii?Q?IK+oAcwNfp6Cazi/Ol2mTa4Ioz6YeKGzdx1tIOz97V44WDz5Pq/AmRuInq+Z?= =?us-ascii?Q?2zpjpjmushV6+iEyjyIkHDaFesFIXAmNEuUHT4nuOrxD+u+zbXGLAZmsRC4Y?= =?us-ascii?Q?mzhZQ5y9eXIE8xhR8G7muSfJ?= Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB7PR08MB2953 Original-Authentication-Results: networkplumber.org; dkim=none (message not signed) header.d=none; networkplumber.org; dmarc=none action=none header.from=arm.com; X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: DB5EUR03FT032.eop-EUR03.prod.protection.outlook.com X-MS-Office365-Filtering-Correlation-Id-Prvs: c1fcef2c-63d8-4980-7017-08d8f260c459 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: H4NlVip1AtDQlEmKVdrb6PoQ3Ec4uMtmP4Edq1j3oeNEdcPe45BcYAVAOegjVcHfSHdh+E/mVCjs2p5fgc57B4QvmEoR9DSwLhCGAk0rwaHRrzUoOhHLyfPXUwU87xW1ChBxqqtE2rKsNFJf8cJLNSXbfUow1Z/rUDMLc0yryc4SI0nYgR4kXiTcNZJ9G4MWTD/svtTLoN+uQKCvsbB+C9mcliW52FkFNH92NeDrQNhqSoDoPkZb1RpGBURiGz6wfflNameAIcCJSllI/Rr5p9n0XU95n2Mf5hRpPkc3cNYT7Cq/GaUuy+vGk3RErCLwYZpvkFdj3+19z/w1VaSsdXJsdZMugYhpJ6X+4IxvTvCqZkfBFZK7OiT7sfONFWiht2N2ScxgQxT02NGz6VVQuOUxrjNfrPbDnPKRYA54ScnousN675coHZ1HqsMxawVFr2GBAm9uLs4G0+l2XDNJkN4YKrZCm7et8tP/UoeBzCBXBndRPJ2jUKhMxN0+Peg156Vlp09U4szx7vDZEKH94yQnlWJ2qW+mZx5IHprCq4UFP3TjfKZyPKVytaeRSE7RhysoW/PQ8hLTSqQNO0A17d/KJ8BNjOhAcAhVjo5OYIN1YHA3AjqXEMOojwR4wPobxcoR3IiwXxROqleuXfKW/lW4ukf3V1WzMTFDlTq7RIKnZOnLyod488e2pqyZwJeV86ZfQpgKvMfwBz2oZ7zYAsP0+0OsVBVpQAQnd1pxrNQ= X-Forefront-Antispam-Report: CIP:63.35.35.123; CTRY:IE; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:64aa7808-outbound-1.mta.getcheckrecipient.com; PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com; CAT:NONE; SFS:(4636009)(376002)(346002)(39860400002)(396003)(136003)(46966006)(36840700001)(86362001)(55016002)(45080400002)(33656002)(966005)(70206006)(336012)(356005)(478600001)(47076005)(36860700001)(6506007)(9686003)(4326008)(52536014)(5660300002)(30864003)(82740400003)(316002)(82310400003)(26005)(81166007)(2906002)(7696005)(8936002)(110136005)(54906003)(8676002)(186003)(83380400001)(70586007); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Mar 2021 03:14:37.7963 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 858be6d0-35ed-475e-46bb-08d8f260c920 X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d; Ip=[63.35.35.123]; Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: DB5EUR03FT032.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR08MB4303 Subject: Re: [dpdk-dev] [PATCH v3] pflock: implementation of phase-fair reader writer locks X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" > Subject: [PATCH v3] pflock: implementation of phase-fair reader writer lo= cks >=20 > This is a new type of reader-writer lock that provides better fairness > guarantees which makes it better for typical DPDK applications. > They lock internally uses two ticket pools, one for readers and one for ^^^^ The > writers. >=20 > Phase fair reader writer locks ensure that neither reader or writer will = be > starved. Neither reader or writer are preferred, they execute in alternat= ing > phases. All operations of the same time (reader or writer) that try to ac= quire ^^^^ type > the lock are handled in FIFO order. Write operations are exclusive, and > multiple read operations can be run together (until a write arrives). >=20 > A similar implementation is in Concurrency Kit package in FreeBSD. > For more information see: > "Reader-Writer Synchronization for Shared-Memory Multiprocessor > Real-Time Systems", > http://www.cs.unc.edu/~anderson/papers/ecrts09b.pdf >=20 > Signed-off-by: Stephen Hemminger > --- > v3 - fix some spelling errors inherited in app/test/test_pflock >=20 > app/test/meson.build | 6 + > app/test/test_pflock.c | 542 ++++++++++++++++++++ > lib/librte_eal/arm/include/meson.build | 1 + > lib/librte_eal/arm/include/rte_pflock.h | 18 + > lib/librte_eal/include/generic/rte_pflock.h | 273 ++++++++++ > lib/librte_eal/ppc/include/meson.build | 1 + > lib/librte_eal/ppc/include/rte_pflock.h | 16 + > lib/librte_eal/x86/include/meson.build | 1 + > lib/librte_eal/x86/include/rte_pflock.h | 18 + > 9 files changed, 876 insertions(+) > create mode 100644 app/test/test_pflock.c create mode 100644 > lib/librte_eal/arm/include/rte_pflock.h > create mode 100644 lib/librte_eal/include/generic/rte_pflock.h > create mode 100644 lib/librte_eal/ppc/include/rte_pflock.h > create mode 100644 lib/librte_eal/x86/include/rte_pflock.h >=20 > diff --git a/app/test/meson.build b/app/test/meson.build index > 561e493a2944..134098de9ac2 100644 > --- a/app/test/meson.build > +++ b/app/test/meson.build > @@ -90,6 +90,7 @@ test_sources =3D files('commands.c', > 'test_mcslock.c', > 'test_mp_secondary.c', > 'test_per_lcore.c', > + 'test_pflock.c', > 'test_pmd_perf.c', > 'test_power.c', > 'test_power_cpufreq.c', > @@ -228,6 +229,11 @@ fast_tests =3D [ > ['meter_autotest', true], > ['multiprocess_autotest', false], > ['per_lcore_autotest', true], > + ['pflock_autotest', true], > + ['pflock_test1_autotest', true], > + ['pflock_rda_autotest', true], > + ['pflock_rds_wrm_autotest', true], > + ['pflock_rde_wro_autotest', true], > ['prefetch_autotest', true], > ['rcu_qsbr_autotest', true], > ['red_autotest', true], > diff --git a/app/test/test_pflock.c b/app/test/test_pflock.c new file mod= e > 100644 index 000000000000..f46610b73914 > --- /dev/null > +++ b/app/test/test_pflock.c > @@ -0,0 +1,542 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2014 Intel Corporation */ Update the copyright > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "test.h" > + > +/* > + * phase fair lock test > + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + * Provides UT for phase fair lock API. > + * Main concern is on functional testing, but also provides some > + * performance measurements. > + * Obviously for proper testing need to be executed with more than one > lcore. > + */ > + > +#define ITER_NUM 0x80 > + > +#define TEST_SEC 5 > + > +static rte_pflock_t sl; > +static rte_pflock_t sl_tab[RTE_MAX_LCORE]; static uint32_t synchro; > + > +enum { > + LC_TYPE_RDLOCK, > + LC_TYPE_WRLOCK, > +}; > + > +static struct { > + rte_pflock_t lock; > + uint64_t tick; > + volatile union { > + uint8_t u8[RTE_CACHE_LINE_SIZE]; > + uint64_t u64[RTE_CACHE_LINE_SIZE / sizeof(uint64_t)]; > + } data; > +} __rte_cache_aligned try_pflock_data; > + > +struct try_pflock_lcore { > + int32_t rc; > + int32_t type; > + struct { > + uint64_t tick; > + uint64_t fail; > + uint64_t success; > + } stat; > +} __rte_cache_aligned; > + > +static struct try_pflock_lcore try_lcore_data[RTE_MAX_LCORE]; > + > +static int > +test_pflock_per_core(__rte_unused void *arg) { > + rte_pflock_write_lock(&sl); > + printf("Global write lock taken on core %u\n", rte_lcore_id()); > + rte_pflock_write_unlock(&sl); > + > + rte_pflock_write_lock(&sl_tab[rte_lcore_id()]); > + printf("Hello from core %u !\n", rte_lcore_id()); > + rte_pflock_write_unlock(&sl_tab[rte_lcore_id()]); > + > + rte_pflock_read_lock(&sl); > + printf("Global read lock taken on core %u\n", rte_lcore_id()); > + rte_delay_ms(100); > + printf("Release global read lock on core %u\n", rte_lcore_id()); > + rte_pflock_read_unlock(&sl); > + > + return 0; > +} > + > +static rte_pflock_t lk =3D RTE_PFLOCK_INITIALIZER; static volatile > +uint64_t pflock_data; static uint64_t time_count[RTE_MAX_LCORE] =3D {0}; > + > +#define MAX_LOOP 10000 > +#define TEST_PFLOCK_DEBUG 0 > + > +static int > +load_loop_fn(__rte_unused void *arg) > +{ > + uint64_t time_diff =3D 0, begin; > + uint64_t hz =3D rte_get_timer_hz(); > + uint64_t lcount =3D 0; > + const unsigned int lcore =3D rte_lcore_id(); > + > + /* wait synchro for workers */ > + if (lcore !=3D rte_get_main_lcore()) > + rte_wait_until_equal_32(&synchro, 1, __ATOMIC_RELAXED); > + > + begin =3D rte_rdtsc_precise(); > + while (lcount < MAX_LOOP) { > + rte_pflock_write_lock(&lk); > + ++pflock_data; > + rte_pflock_write_unlock(&lk); > + > + rte_pflock_read_lock(&lk); > + if (TEST_PFLOCK_DEBUG && !(lcount % 100)) > + printf("Core [%u] pflock_data =3D %"PRIu64"\n", > + lcore, pflock_data); > + rte_pflock_read_unlock(&lk); > + > + lcount++; > + /* delay to make lock duty cycle slightly realistic */ > + rte_pause(); > + } > + > + time_diff =3D rte_rdtsc_precise() - begin; > + time_count[lcore] =3D time_diff * 1000000 / hz; > + return 0; > +} > + > +static int > +test_pflock_perf(void) > +{ > + unsigned int i; > + uint64_t total =3D 0; > + > + printf("\nPhase fair test on %u cores...\n", rte_lcore_count()); > + > + /* clear synchro and start workers */ > + synchro =3D 0; > + if (rte_eal_mp_remote_launch(load_loop_fn, NULL, SKIP_MAIN) < > 0) > + return -1; > + > + /* start synchro and launch test on main */ > + __atomic_store_n(&synchro, 1, __ATOMIC_RELAXED); > + load_loop_fn(NULL); > + > + rte_eal_mp_wait_lcore(); > + > + RTE_LCORE_FOREACH(i) { > + printf("Core [%u] cost time =3D %"PRIu64" us\n", > + i, time_count[i]); > + total +=3D time_count[i]; > + } > + > + printf("Total cost time =3D %"PRIu64" us\n", total); > + memset(time_count, 0, sizeof(time_count)); > + > + return 0; > +} > + > +/* > + * - There is a global pflock and a table of pflocks (one per lcore). > + * > + * - The test function takes all of these locks and launches the > + * ``test_pflock_per_core()`` function on each core (except the main). > + * > + * - The function takes the global write lock, display something, > + * then releases the global lock. > + * - Then, it takes the per-lcore write lock, display something, and > + * releases the per-core lock. > + * - Finally, a read lock is taken during 100 ms, then released. > + * > + * - The main function unlocks the per-lcore locks sequentially and > + * waits between each lock. This triggers the display of a message > + * for each core, in the correct order. > + * > + * Then, it tries to take the global write lock and display the last > + * message. The autotest script checks that the message order is corre= ct. > + */ > +static int > +pflock_test1(void) > +{ > + int i; > + > + rte_pflock_init(&sl); > + for (i =3D 0; i < RTE_MAX_LCORE; i++) > + rte_pflock_init(&sl_tab[i]); > + > + rte_pflock_write_lock(&sl); > + > + RTE_LCORE_FOREACH_WORKER(i) { > + rte_pflock_write_lock(&sl_tab[i]); > + rte_eal_remote_launch(test_pflock_per_core, NULL, i); > + } > + > + rte_pflock_write_unlock(&sl); > + > + RTE_LCORE_FOREACH_WORKER(i) { > + rte_pflock_write_unlock(&sl_tab[i]); > + rte_delay_ms(100); > + } > + > + rte_pflock_write_lock(&sl); > + /* this message should be the last message of test */ > + printf("Global write lock taken on main core %u\n", rte_lcore_id()); > + rte_pflock_write_unlock(&sl); > + > + rte_eal_mp_wait_lcore(); > + > + if (test_pflock_perf() < 0) > + return -1; > + > + return 0; > +} > + > +static int > +test_pflock(void) > +{ > + uint32_t i; > + int32_t rc, ret; > + > + static const struct { > + const char *name; > + int (*ftst)(void); > + } test[] =3D { > + { > + .name =3D "pflock_test1", > + .ftst =3D pflock_test1, > + }, > + }; > + > + ret =3D 0; > + for (i =3D 0; i !=3D RTE_DIM(test); i++) { > + printf("starting test %s;\n", test[i].name); > + rc =3D test[i].ftst(); > + printf("test %s completed with status %d\n", test[i].name, > rc); > + ret |=3D rc; > + } > + > + return ret; > +} > + > +static int > +try_read(uint32_t lc) > +{ > + int32_t rc; > + uint32_t i; > + > + rc =3D rte_pflock_read_trylock(&try_pflock_data.lock); > + if (rc !=3D 0) > + return rc; > + > + for (i =3D 0; i !=3D RTE_DIM(try_pflock_data.data.u64); i++) { > + > + /* race condition occurred, lock doesn't work properly */ > + if (try_pflock_data.data.u64[i] !=3D 0) { > + printf("%s(%u) error: unexpected data pattern\n", > + __func__, lc); > + rte_memdump(stdout, NULL, > + (void *)(uintptr_t)&try_pflock_data.data, > + sizeof(try_pflock_data.data)); > + rc =3D -EFAULT; > + break; > + } > + } > + > + rte_pflock_read_unlock(&try_pflock_data.lock); > + return rc; > +} > + > +static int > +try_write(uint32_t lc) > +{ > + int32_t rc; > + uint32_t i, v; > + > + v =3D RTE_MAX(lc % UINT8_MAX, 1U); > + > + rc =3D rte_pflock_write_trylock(&try_pflock_data.lock); > + if (rc !=3D 0) > + return rc; > + > + /* update by bytes in reverse order */ > + for (i =3D RTE_DIM(try_pflock_data.data.u8); i-- !=3D 0; ) { > + > + /* race condition occurred, lock doesn't work properly */ > + if (try_pflock_data.data.u8[i] !=3D 0) { > + printf("%s:%d(%u) error: unexpected data > pattern\n", > + __func__, __LINE__, lc); > + rte_memdump(stdout, NULL, > + (void *)(uintptr_t)&try_pflock_data.data, > + sizeof(try_pflock_data.data)); > + rc =3D -EFAULT; > + break; > + } > + > + try_pflock_data.data.u8[i] =3D v; > + } > + > + /* restore by bytes in reverse order */ > + for (i =3D RTE_DIM(try_pflock_data.data.u8); i-- !=3D 0; ) { > + > + /* race condition occurred, lock doesn't work properly */ > + if (try_pflock_data.data.u8[i] !=3D v) { > + printf("%s:%d(%u) error: unexpected data > pattern\n", > + __func__, __LINE__, lc); > + rte_memdump(stdout, NULL, > + (void *)(uintptr_t)&try_pflock_data.data, > + sizeof(try_pflock_data.data)); > + rc =3D -EFAULT; > + break; > + } > + > + try_pflock_data.data.u8[i] =3D 0; > + } > + > + rte_pflock_write_unlock(&try_pflock_data.lock); > + return rc; > +} > + > +static int > +try_read_lcore(__rte_unused void *data) { > + int32_t rc; > + uint32_t i, lc; > + uint64_t ftm, stm, tm; > + struct try_pflock_lcore *lcd; > + > + lc =3D rte_lcore_id(); > + lcd =3D try_lcore_data + lc; > + lcd->type =3D LC_TYPE_RDLOCK; > + > + ftm =3D try_pflock_data.tick; > + stm =3D rte_get_timer_cycles(); > + > + do { > + for (i =3D 0; i !=3D ITER_NUM; i++) { > + rc =3D try_read(lc); > + if (rc =3D=3D 0) > + lcd->stat.success++; > + else if (rc =3D=3D -EBUSY) > + lcd->stat.fail++; > + else > + break; > + rc =3D 0; > + } > + tm =3D rte_get_timer_cycles() - stm; > + } while (tm < ftm && rc =3D=3D 0); > + > + lcd->rc =3D rc; > + lcd->stat.tick =3D tm; > + return rc; > +} > + > +static int > +try_write_lcore(__rte_unused void *data) { > + int32_t rc; > + uint32_t i, lc; > + uint64_t ftm, stm, tm; > + struct try_pflock_lcore *lcd; > + > + lc =3D rte_lcore_id(); > + lcd =3D try_lcore_data + lc; > + lcd->type =3D LC_TYPE_WRLOCK; > + > + ftm =3D try_pflock_data.tick; > + stm =3D rte_get_timer_cycles(); > + > + do { > + for (i =3D 0; i !=3D ITER_NUM; i++) { > + rc =3D try_write(lc); > + if (rc =3D=3D 0) > + lcd->stat.success++; > + else if (rc =3D=3D -EBUSY) > + lcd->stat.fail++; > + else > + break; > + rc =3D 0; > + } > + tm =3D rte_get_timer_cycles() - stm; > + } while (tm < ftm && rc =3D=3D 0); > + > + lcd->rc =3D rc; > + lcd->stat.tick =3D tm; > + return rc; > +} > + > +static void > +print_try_lcore_stats(const struct try_pflock_lcore *tlc, uint32_t lc) > +{ > + uint64_t f, s; > + > + f =3D RTE_MAX(tlc->stat.fail, 1ULL); > + s =3D RTE_MAX(tlc->stat.success, 1ULL); > + > + printf("try_lcore_data[%u]=3D{\n" > + "\trc=3D%d,\n" > + "\ttype=3D%s,\n" > + "\tfail=3D%" PRIu64 ",\n" > + "\tsuccess=3D%" PRIu64 ",\n" > + "\tcycles=3D%" PRIu64 ",\n" > + "\tcycles/op=3D%#Lf,\n" > + "\tcycles/success=3D%#Lf,\n" > + "\tsuccess/fail=3D%#Lf,\n" > + "};\n", > + lc, > + tlc->rc, > + tlc->type =3D=3D LC_TYPE_RDLOCK ? "RDLOCK" : "WRLOCK", > + tlc->stat.fail, > + tlc->stat.success, > + tlc->stat.tick, > + (long double)tlc->stat.tick / > + (tlc->stat.fail + tlc->stat.success), > + (long double)tlc->stat.tick / s, > + (long double)tlc->stat.success / f); > +} > + > +static void > +collect_try_lcore_stats(struct try_pflock_lcore *tlc, > + const struct try_pflock_lcore *lc) > +{ > + tlc->stat.tick +=3D lc->stat.tick; > + tlc->stat.fail +=3D lc->stat.fail; > + tlc->stat.success +=3D lc->stat.success; } > + > +/* > + * Process collected results: > + * - check status > + * - collect and print statistics > + */ > +static int > +process_try_lcore_stats(void) > +{ > + int32_t rc; > + uint32_t lc, rd, wr; > + struct try_pflock_lcore rlc, wlc; > + > + memset(&rlc, 0, sizeof(rlc)); > + memset(&wlc, 0, sizeof(wlc)); > + > + rlc.type =3D LC_TYPE_RDLOCK; > + wlc.type =3D LC_TYPE_WRLOCK; > + rd =3D 0; > + wr =3D 0; > + > + rc =3D 0; > + RTE_LCORE_FOREACH(lc) { > + rc |=3D try_lcore_data[lc].rc; > + if (try_lcore_data[lc].type =3D=3D LC_TYPE_RDLOCK) { > + collect_try_lcore_stats(&rlc, try_lcore_data + lc); > + rd++; > + } else { > + collect_try_lcore_stats(&wlc, try_lcore_data + lc); > + wr++; > + } > + } > + > + if (rc =3D=3D 0) { > + RTE_LCORE_FOREACH(lc) > + print_try_lcore_stats(try_lcore_data + lc, lc); > + > + if (rd !=3D 0) { > + printf("aggregated stats for %u RDLOCK cores:\n", > rd); > + print_try_lcore_stats(&rlc, rd); > + } > + > + if (wr !=3D 0) { > + printf("aggregated stats for %u WRLOCK cores:\n", > wr); > + print_try_lcore_stats(&wlc, wr); > + } > + } > + > + return rc; > +} > + > +static void > +try_test_reset(void) > +{ > + memset(&try_lcore_data, 0, sizeof(try_lcore_data)); > + memset(&try_pflock_data, 0, sizeof(try_pflock_data)); > + try_pflock_data.tick =3D TEST_SEC * rte_get_tsc_hz(); } > + > +/* all lcores grab RDLOCK */ > +static int > +try_pflock_test_rda(void) > +{ > + try_test_reset(); > + > + /* start read test on all available lcores */ > + rte_eal_mp_remote_launch(try_read_lcore, NULL, CALL_MAIN); > + rte_eal_mp_wait_lcore(); > + > + return process_try_lcore_stats(); > +} > + > +/* all worker lcores grab RDLOCK, main one grabs WRLOCK */ static int > +try_pflock_test_rds_wrm(void) > +{ > + try_test_reset(); > + > + rte_eal_mp_remote_launch(try_read_lcore, NULL, SKIP_MAIN); > + try_write_lcore(NULL); > + rte_eal_mp_wait_lcore(); > + > + return process_try_lcore_stats(); > +} > + > +/* main and even worker lcores grab RDLOCK, odd lcores grab WRLOCK */ > +static int > +try_pflock_test_rde_wro(void) > +{ > + uint32_t lc, mlc; > + > + try_test_reset(); > + > + mlc =3D rte_get_main_lcore(); > + > + RTE_LCORE_FOREACH(lc) { > + if (lc !=3D mlc) { > + if ((lc & 1) =3D=3D 0) > + rte_eal_remote_launch(try_read_lcore, > + NULL, lc); > + else > + rte_eal_remote_launch(try_write_lcore, > + NULL, lc); > + } > + } > + try_read_lcore(NULL); > + rte_eal_mp_wait_lcore(); > + > + return process_try_lcore_stats(); > +} > + > +REGISTER_TEST_COMMAND(pflock_autotest, test_pflock); > + > +/* subtests used in meson for CI */ > +REGISTER_TEST_COMMAND(pflock_test1_autotest, pflock_test1); > +REGISTER_TEST_COMMAND(pflock_rda_autotest, try_pflock_test_rda); > +REGISTER_TEST_COMMAND(pflock_rds_wrm_autotest, > +try_pflock_test_rds_wrm); > +REGISTER_TEST_COMMAND(pflock_rde_wro_autotest, > +try_pflock_test_rde_wro); > diff --git a/lib/librte_eal/arm/include/meson.build > b/lib/librte_eal/arm/include/meson.build > index 770766de1a34..2c3cff61bed6 100644 > --- a/lib/librte_eal/arm/include/meson.build > +++ b/lib/librte_eal/arm/include/meson.build > @@ -21,6 +21,7 @@ arch_headers =3D files( > 'rte_pause_32.h', > 'rte_pause_64.h', > 'rte_pause.h', > + 'rte_pflock.h', > 'rte_power_intrinsics.h', > 'rte_prefetch_32.h', > 'rte_prefetch_64.h', > diff --git a/lib/librte_eal/arm/include/rte_pflock.h > b/lib/librte_eal/arm/include/rte_pflock.h > new file mode 100644 > index 000000000000..bb9934eec469 > --- /dev/null > +++ b/lib/librte_eal/arm/include/rte_pflock.h > @@ -0,0 +1,18 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2021 Microsoft Corporation */ > + > +#ifndef _RTE_PFLOCK_ARM_H_ > +#define _RTE_PFLOCK_ARM_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include "generic/rte_pflock.h" > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_PFLOCK_ARM_H_ */ > diff --git a/lib/librte_eal/include/generic/rte_pflock.h > b/lib/librte_eal/include/generic/rte_pflock.h > new file mode 100644 > index 000000000000..6808c70c34a2 > --- /dev/null > +++ b/lib/librte_eal/include/generic/rte_pflock.h > @@ -0,0 +1,273 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2021 Microsoft Corp. > + * Copyright 2011-2015 Samy Al Bahra. Any reason for adding the above copy right? > + * All rights reserved. > + */ > + > +#ifndef _RTE_PFLOCK_H_ > +#define _RTE_PFLOCK_H_ > + > +/** > + * @file > + * > + * Phase-fair locks > + * > + * This file defines an API for Phase Fair reader writer locks, > + * which is a variant of typical reader-writer locks that prevent > + * starvation. In this type of lock, readers and writers alternate. > + * This significantly reduces the worst-case blocking for readers and wr= iters. > + * > + * This is an implementation derived from FreeBSD > + * based on the work described in: > + * Brandenburg, B. and Anderson, J. 2010. Spin-Based > + * Reader-Writer Synchronization for Multiprocessor Real-Time Systems > + * > + * All locks must be initialised before use, and only initialised once. > + */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include > +#include > + > +/** > + * The rte_pflock_t type. > + */ > +struct rte_pflock { > + union rte_pflock_ticket { > + uint32_t tickets; > + struct { > + uint16_t in; > + uint16_t out; > + }; > + } rd, wr; Just wondering if placing these on 2 different cache lines would help the p= erformance? > +}; > +typedef struct rte_pflock rte_pflock_t; > + > +/** > + * Constants used to map the bits in reader counter > + * > + * +-----------------+-+-+ > + * | Readers |W|P| > + * | |R|H| > + * +-----------------+-+-+ It would be good to indicate the reserved part. > + */ > + > +#define RTE_PFLOCK_LSB 0xFFF0 Based on the value of RTE_PFLOCK_RINC, should this be 0xFF00?=20 > +#define RTE_PFLOCK_RINC 0x100 /* Reader increment value. Does this mean, there can be only 256 concurrent readers? > */ > +#define RTE_PFLOCK_WBITS 0x3 /* Writer bits in reader. */ > +#define RTE_PFLOCK_PRES 0x2 /* Writer present bit. */ > +#define RTE_PFLOCK_PHID 0x1 /* Phase ID bit. */ > + > +/** > + * A static pflock initializer. > + */ > +#define RTE_PFLOCK_INITIALIZER { } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Initialize the pflock to an unlocked state. > + * > + * @param pf > + * A pointer to the pflock. > + */ > +__rte_experimental > +static inline void > +rte_pflock_init(struct rte_pflock *pf) > +{ > + pf->rd.tickets =3D 0; > + pf->wr.tickets =3D 0; > +} > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Take a pflock for read. > + * > + * @param pf > + * A pointer to a pflock structure. > + */ > +__rte_experimental > +static inline void > +rte_pflock_read_lock(rte_pflock_t *pf) > +{ > + uint32_t w; > + > + /* > + * If no writer is present, then the operation has completed > + * successfully. > + */ > + w =3D __atomic_fetch_add(&pf->rd.in, RTE_PFLOCK_RINC, > __ATOMIC_ACQ_REL) & RTE_PFLOCK_WBITS; Any reason for the RELEASE? I think ACQUIRE is enough as the write to rd.in= is not releasing any previous memory operations. > + if (w =3D=3D 0) > + return; > + > + /* Wait for current write phase to complete. */ > + while ((__atomic_load_n(&pf->rd.in, __ATOMIC_ACQUIRE) & > RTE_PFLOCK_WBITS) =3D=3D w) > + rte_pause(); > +} > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Release a pflock locked for reading. > + * > + * @param pf > + * A pointer to the pflock structure. > + */ > +__rte_experimental > +static inline void > +rte_pflock_read_unlock(rte_pflock_t *pf) { > + __atomic_fetch_add(&pf->rd.out, RTE_PFLOCK_RINC, > __ATOMIC_RELEASE); } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Try to take a pflock for reading > + * > + * @param pf > + * A pointer to a pflock structure. > + * @return > + * - zero if the lock is successfully taken > + * - -EBUSY if lock could not be acquired for reading because a > + * writer holds the lock > + */ > +__rte_experimental > +static inline int > +rte_pflock_read_trylock(rte_pflock_t *pf) { > + union rte_pflock_ticket old, new; > + > + /* Get current state of the lock */ > + old.tickets =3D __atomic_load_n(&pf->rd.tickets, > __ATOMIC_RELAXED); > + > + /* loop until writer shows up */ > + while ((old.in & RTE_PFLOCK_WBITS) =3D=3D 0) { > + new.out =3D old.out; > + new.in =3D old.in + RTE_PFLOCK_RINC; > + if (__atomic_compare_exchange_n(&pf->rd.tickets, > &old.tickets, new.tickets, > + 0, __ATOMIC_ACQ_REL, = ^^^ I think ACQUIRE is enou= gh. We are not releasing anything to other threads. > __ATOMIC_RELAXED)) > + return 0; /* got it */ > + > + /* either new reader got in (so retry) or a writer */ > + } > + > + /* If writer is present then we are busy */ > + return -EBUSY; > +} > + > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Take the pflock for write. > + * > + * @param pf > + * A pointer to the ticketlock. > + */ > +__rte_experimental > +static inline void > +rte_pflock_write_lock(rte_pflock_t *pf) { > + uint16_t ticket; > + > + /* Acquire ownership of write-phase. */ > + ticket =3D __atomic_fetch_add(&pf->wr.in, 1, __ATOMIC_ACQUIRE); > + rte_wait_until_equal_16(&pf->wr.out, ticket, __ATOMIC_RELAXED); > + > + /* > + * Acquire ticket on read-side in order to allow them > + * to flush. Indicates to any incoming reader that a > + * write-phase is pending. > + * > + * Need ACQUIRE to prevent speculative execution of the wait loop I do not think the entire wait loop will be executed speculatively. Only th= e load of pf->rd.out would happen speculatively. There is a dependency on '= ticket' variable. So, the load of the 'ticket' variable should happen after= 'ticket' is updated below. =20 > + */ > + ticket =3D __atomic_fetch_add(&pf->rd.in, > + (ticket & RTE_PFLOCK_PHID) | > RTE_PFLOCK_PRES, > + __ATOMIC_ACQUIRE); Since, it is ok to execute part of the wait loop above this. We could make = this RELAXED. Also, since we just need to set the 2 bits, is it better to use __atomic_fe= tch_or? It also matches with the use of __atomic_fetch_and in the unlock AP= I. > + > + /* Wait for any pending readers to flush. */ > + rte_wait_until_equal_16(&pf->rd.out, ticket, __ATOMIC_RELAXED); RELAXED here will allow the critical section to execute above the wait loop= . Hence it is better to make this ACQUIRE. > } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Release a pflock held for writing. > + * > + * @param pf > + * A pointer to a pflock structure. > + */ > +__rte_experimental > +static inline void > +rte_pflock_write_unlock(rte_pflock_t *pf) { > + /* Migrate from write phase to read phase. */ > + __atomic_fetch_and(&pf->rd.in, RTE_PFLOCK_LSB, > __ATOMIC_RELEASE); > + > + /* Allow other writers to continue. */ > + __atomic_fetch_add(&pf->wr.out, 1, __ATOMIC_RELEASE); } > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice. > + * > + * Try to take the pflock for write. > + * > + * @param pf > + * A pointer to the pflock. > + * @return > + * - zero if the lock is successfully taken > + * - -EBUSY if lock could not be acquired for writing because > + * another writer holds the lock What about the readers holding the lock? > + */ > +__rte_experimental > +static inline int > +rte_pflock_write_trylock(rte_pflock_t *pf) { > + union rte_pflock_ticket old, new; > + uint16_t ticket; > + > + /* Get current state of the lock */ > + old.tickets =3D __atomic_load_n(&pf->wr.tickets, > __ATOMIC_RELAXED); > + new.out =3D old.out; > + new.in =3D old.in + 1; > + ticket =3D new.in; > + > + /* if writer is already present then too busy */ > + if (old.out !=3D new.in || > + !__atomic_compare_exchange_n(&pf->wr.tickets, &old.tickets, > new.tickets, > + 0, __ATOMIC_ACQ_REL, > __ATOMIC_RELAXED)) > + return -EBUSY; /* another writer is present already */ > + > + /* > + * We now own the write phase, but still need to tell > + * readers and wait for them. The write lock is taken if there are no readers AND no writers (unlike the = read lock which is taken if there are no writers waiting (only)) Since this is a try lock, should we wait for the readers to give up the loc= k? I think, if the readers are present, we should give up the writer phase and= return.=20 > + * > + * Need ACQUIRE semantics to avoid speculative execution of wait > loop > + */ > + ticket =3D __atomic_fetch_add(&pf->rd.in, > + (ticket & RTE_PFLOCK_PHID) | > RTE_PFLOCK_PRES, > + __ATOMIC_ACQUIRE); > + > + /* Wait for any pending readers to flush. */ > + rte_wait_until_equal_16(&pf->rd.out, ticket, __ATOMIC_RELAXED); > + return 0; > +} > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* RTE_PFLOCK_H */ > diff --git a/lib/librte_eal/ppc/include/meson.build > b/lib/librte_eal/ppc/include/meson.build > index dae40ede546e..7692a531ccba 100644 > --- a/lib/librte_eal/ppc/include/meson.build > +++ b/lib/librte_eal/ppc/include/meson.build > @@ -11,6 +11,7 @@ arch_headers =3D files( > 'rte_mcslock.h', > 'rte_memcpy.h', > 'rte_pause.h', > + 'rte_pflock.h', > 'rte_power_intrinsics.h', > 'rte_prefetch.h', > 'rte_rwlock.h', > diff --git a/lib/librte_eal/ppc/include/rte_pflock.h > b/lib/librte_eal/ppc/include/rte_pflock.h > new file mode 100644 > index 000000000000..e7b875ac56a8 > --- /dev/null > +++ b/lib/librte_eal/ppc/include/rte_pflock.h > @@ -0,0 +1,16 @@ > +/* SPDX-License-Identifier: BSD-3-Clause */ #ifndef Copyright header missing? > +_RTE_PFLOCK_PPC_64_H_ #define _RTE_PFLOCK_PPC_64_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include "generic/rte_pflock.h" > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_PFLOCK_PPC_64_H_ */ > diff --git a/lib/librte_eal/x86/include/meson.build > b/lib/librte_eal/x86/include/meson.build > index 1a6ad0b17342..f43645c20899 100644 > --- a/lib/librte_eal/x86/include/meson.build > +++ b/lib/librte_eal/x86/include/meson.build > @@ -10,6 +10,7 @@ arch_headers =3D files( > 'rte_mcslock.h', > 'rte_memcpy.h', > 'rte_pause.h', > + 'rte_pflock.h', > 'rte_power_intrinsics.h', > 'rte_prefetch.h', > 'rte_rtm.h', > diff --git a/lib/librte_eal/x86/include/rte_pflock.h > b/lib/librte_eal/x86/include/rte_pflock.h > new file mode 100644 > index 000000000000..c2d876062c08 > --- /dev/null > +++ b/lib/librte_eal/x86/include/rte_pflock.h > @@ -0,0 +1,18 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2021 Microsoft Corporation */ > + > +#ifndef _RTE_PFLOCK_X86_64_H_ > +#define _RTE_PFLOCK_X86_64_H_ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include "generic/rte_pflock.h" > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* _RTE_PFLOCK_X86_64_H_ */ > -- > 2.30.1