From patchwork Sun Apr 26 15:28:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Kozlyuk X-Patchwork-Id: 69346 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id D7CEAA00C5; Sun, 26 Apr 2020 17:28:41 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id BD14B1BF7C; Sun, 26 Apr 2020 17:28:37 +0200 (CEST) Received: from mail-lj1-f195.google.com (mail-lj1-f195.google.com [209.85.208.195]) by dpdk.org (Postfix) with ESMTP id 8B4051BF76 for ; Sun, 26 Apr 2020 17:28:35 +0200 (CEST) Received: by mail-lj1-f195.google.com with SMTP id u6so14875535ljl.6 for ; Sun, 26 Apr 2020 08:28:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=LASgUL8hC+j7pJoeqp6DAm/7OlzxzL2wo2kXynbJyZ8=; b=O7Q42Gb8iWkVTaGjQMgedESsllTofaujTFo2cdA/5RmBZqEvcAG3LpZE5xyatefDiv FQvKIwrdVhIJnyDel7tn6MahYKCXpZEiHXskppN2DDVtmqmByZ2tzzJ1FAC4/9h8wNWz ulqkFszj8w9tYxT/2n45bnEVOSWFtfUdaapBg6QLwAUhwOq9j5HizcPRL/DUwubtxf4w 8lq9H1yYI+IzROi/lgqqNiZ9zgV2uH2pMnFEcoTRQy3O0BfsybPYLS/BPbLquAOnG5yL Tvy022vt6YnBtYjnDvWIBRslMRvf/hkbT5yS351XtdoCPM8Ow7lQ6StzPyjpAG8+Gn52 0pPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LASgUL8hC+j7pJoeqp6DAm/7OlzxzL2wo2kXynbJyZ8=; b=p5gHN7zauDEjHEMYLltZ5HPRviP80ca2rA+MCF5/k/7NcnGltNcrpohKZz2hz9TM+w DHOpBC8+pPLfMTHRleZP51rMJAoExvgH1Wx+H1nlnCyq/SM4+9H2K4fuxW7v+b6oCPhk I2CfIkRGFZaSFxvS//7ZN3EcHx4Lpw6PjAWaINpR7vXTlnOrRq2lGbOQKSBWLJSzPIXg ojG/Oz85CfZWwp3AHOBeoVwfCaRMrwziy9FDdKme5hN5XAxpJXHX7FZat7fY5blG18NB cehD0/i7Ff1Nt/XUNuIvxK5nX5QfUwSF6wJi8ucEwhf3wqhda/IT9B2oJ8OD1582nYHG q18w== X-Gm-Message-State: AGi0PubLnQYALDAzgeEbXyLzyIN02xdgdm2aNjlzRfGuVJig1pOzXcIz f2O6GjxtXiN97y28TGoduE01r+ukAkk= X-Google-Smtp-Source: APiQypJhwIc7rlK6rht8078S69sBiR9sTQZtoPnqYYViHOfan4l6htnfJohPv0OT9NxHskESVdXwjw== X-Received: by 2002:a2e:b5b9:: with SMTP id f25mr11397962ljn.11.1587914914041; Sun, 26 Apr 2020 08:28:34 -0700 (PDT) Received: from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru. [37.110.65.23]) by smtp.googlemail.com with ESMTPSA id p13sm8211340ljg.103.2020.04.26.08.28.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 26 Apr 2020 08:28:33 -0700 (PDT) From: Dmitry Kozlyuk To: dev@dpdk.org Cc: Pallavi Kadam , Narcisa Ana Maria Vasile , Ranjit Menon , Dmitry Kozlyuk , Harini Ramakrishnan , Omar Cardona Date: Sun, 26 Apr 2020 18:28:16 +0300 Message-Id: <20200426152819.2496610-2-dmitry.kozliuk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200426152819.2496610-1-dmitry.kozliuk@gmail.com> References: <20200426032245.2437733-1-dmitry.kozliuk@gmail.com> <20200426152819.2496610-1-dmitry.kozliuk@gmail.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v2 1/3] eal/windows: replace sys/queue.h with a complete one from FreeBSD X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" Limited version imported previously lacks STAILQ macros used by tracing and SLIST macros used by memory management. Import a complete file from FreeBSD, since its license exception is already approved by Technical Board. Signed-off-by: Dmitry Kozlyuk --- lib/librte_eal/windows/include/sys/queue.h | 663 +++++++++++++++++++-- 1 file changed, 601 insertions(+), 62 deletions(-) diff --git a/lib/librte_eal/windows/include/sys/queue.h b/lib/librte_eal/windows/include/sys/queue.h index a65949a78..9756bee6f 100644 --- a/lib/librte_eal/windows/include/sys/queue.h +++ b/lib/librte_eal/windows/include/sys/queue.h @@ -8,7 +8,36 @@ #define _SYS_QUEUE_H_ /* - * This file defines tail queues. + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may be traversed in either direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly @@ -17,65 +46,93 @@ * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * + * For details on the use of these macros, see the queue(3) manual page. + * * Below is a summary of implemented functions where: * + means the macro is available * - means the macro is not available * s means the macro is available but is slow (runs in O(n) time) * - * TAILQ - * _HEAD + - * _CLASS_HEAD + - * _HEAD_INITIALIZER + - * _ENTRY + - * _CLASS_ENTRY + - * _INIT + - * _EMPTY + - * _FIRST + - * _NEXT + - * _PREV + - * _LAST + - * _LAST_FAST + - * _FOREACH + - * _FOREACH_FROM + - * _FOREACH_SAFE + - * _FOREACH_FROM_SAFE + - * _FOREACH_REVERSE + - * _FOREACH_REVERSE_FROM + - * _FOREACH_REVERSE_SAFE + - * _FOREACH_REVERSE_FROM_SAFE + - * _INSERT_HEAD + - * _INSERT_BEFORE + - * _INSERT_AFTER + - * _INSERT_TAIL + - * _CONCAT + - * _REMOVE_AFTER - - * _REMOVE_HEAD - - * _REMOVE + - * _SWAP + + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _CLASS_HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _CLASS_ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - + - + + * _LAST - - + + + * _LAST_FAST - - - + + * _FOREACH + + + + + * _FOREACH_FROM + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_FROM_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_FROM - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _FOREACH_REVERSE_FROM_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT s s + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE s + s + + * _SWAP + + + + * */ - -#ifdef __cplusplus -extern "C" { +#ifdef QUEUE_MACRO_DEBUG +#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH +#define QUEUE_MACRO_DEBUG_TRACE +#define QUEUE_MACRO_DEBUG_TRASH #endif -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} +#ifdef QUEUE_MACRO_DEBUG_TRACE +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + unsigned long lastline; + unsigned long prevline; + const char *lastfile; + const char *prevfile; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else /* !QUEUE_MACRO_DEBUG_TRACE */ #define QMD_TRACE_ELEM(elem) #define QMD_TRACE_HEAD(head) #define TRACEBUF #define TRACEBUF_INITIALIZER +#endif /* QUEUE_MACRO_DEBUG_TRACE */ +#ifdef QUEUE_MACRO_DEBUG_TRASH +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1) +#else /* !QUEUE_MACRO_DEBUG_TRASH */ +#define QMD_SAVELINK(name, link) #define TRASHIT(x) #define QMD_IS_TRASHED(x) 0 - -#define QMD_SAVELINK(name, link) +#endif /* QUEUE_MACRO_DEBUG_TRASH */ #ifdef __cplusplus /* @@ -86,6 +143,445 @@ struct name { \ #define QUEUE_TYPEOF(type) struct type #endif +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +#define SLIST_CLASS_ENTRY(type) \ +struct { \ + class type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \ + if (*(prevp) != (elm)) \ + panic("Bad prevptr *(%p) == %p != %p", \ + (prevp), *(prevp), (elm)); \ +} while (0) +#else +#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) +#endif + +#define SLIST_CONCAT(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \ + if (curelm == NULL) { \ + if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \ + SLIST_INIT(head2); \ + } else if (SLIST_FIRST(head2) != NULL) { \ + while (SLIST_NEXT(curelm, field) != NULL) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \ + SLIST_INIT(head2); \ + } \ +} while (0) + +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \ + QMD_SLIST_CHECK_PREVPTR(prevp, elm); \ + *(prevp) = SLIST_NEXT(elm, field); \ + TRASHIT((elm)->field.sle_next); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *stqh_first; /* first element */ \ + class type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +#define STAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? NULL : \ + __containerof((head)->stqh_last, \ + QUEUE_TYPEOF(type), field.stqe_next)) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ + QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +#define LIST_CLASS_ENTRY(type) \ +struct { \ + class type *le_next; /* next element */ \ + class type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +/* + * QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME) + * + * If the list is non-empty, validates that the first element of the list + * points back at 'head.' + */ +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +/* + * QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME) + * + * If an element follows 'elm' in the list, validates that the next element + * points back at 'elm.' + */ +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +/* + * QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME) + * + * Validates that the previous element (or head of the list) points to 'elm.' + */ +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_CONCAT(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \ + if (curelm == NULL) { \ + if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \ + LIST_FIRST(head2)->field.le_prev = \ + &LIST_FIRST((head1)); \ + LIST_INIT(head2); \ + } \ + } else if (LIST_FIRST(head2) != NULL) { \ + while (LIST_NEXT(curelm, field) != NULL) \ + curelm = LIST_NEXT(curelm, field); \ + LIST_NEXT(curelm, field) = LIST_FIRST(head2); \ + LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \ + LIST_INIT(head2); \ + } \ +} while (0) + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_PREV(elm, head, type, field) \ + ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ + __containerof((elm)->field.le_prev, \ + QUEUE_TYPEOF(type), field.le_next)) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + /* * Tail queue declarations. */ @@ -123,10 +619,58 @@ struct { \ /* * Tail queue functions. */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +/* + * QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME) + * + * If the tailq is non-empty, validates that the first element of the tailq + * points back at 'head.' + */ +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +/* + * QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME) + * + * Validates that the tail of the tailq is a pointer to pointer to NULL. + */ +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +/* + * QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME) + * + * If an element follows 'elm' in the tailq, validates that the next element + * points back at 'elm.' + */ +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +/* + * QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME) + * + * Validates that the previous element (or head of the tailq) points to 'elm.' + */ +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else #define QMD_TAILQ_CHECK_HEAD(head, field) #define QMD_TAILQ_CHECK_TAIL(head, headname) #define QMD_TAILQ_CHECK_NEXT(elm, field) #define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ #define TAILQ_CONCAT(head1, head2, field) do { \ if (!TAILQ_EMPTY(head2)) { \ @@ -191,9 +735,8 @@ struct { \ #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ QMD_TAILQ_CHECK_NEXT(listelm, field); \ - TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field); \ - if (TAILQ_NEXT((listelm), field) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ &TAILQ_NEXT((elm), field); \ else { \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ @@ -217,8 +760,7 @@ struct { \ #define TAILQ_INSERT_HEAD(head, elm, field) do { \ QMD_TAILQ_CHECK_HEAD(head, field); \ - TAILQ_NEXT((elm), field) = TAILQ_FIRST((head)); \ - if (TAILQ_FIRST((head)) != NULL) \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ TAILQ_FIRST((head))->field.tqe_prev = \ &TAILQ_NEXT((elm), field); \ else \ @@ -250,21 +792,24 @@ struct { \ * you may want to prefetch the last data element. */ #define TAILQ_LAST_FAST(head, type, field) \ - (TAILQ_EMPTY(head) ? NULL : __containerof((head)->tqh_last, \ - QUEUE_TYPEOF(type), field.tqe_next)) + (TAILQ_EMPTY(head) ? NULL : __containerof((head)->tqh_last, QUEUE_TYPEOF(type), field.tqe_next)) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_PREV_FAST(elm, head, type, field) \ + ((elm)->field.tqe_prev == &(head)->tqh_first ? NULL : \ + __containerof((elm)->field.tqe_prev, QUEUE_TYPEOF(type), field.tqe_next)) + #define TAILQ_REMOVE(head, elm, field) do { \ QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ QMD_TAILQ_CHECK_NEXT(elm, field); \ QMD_TAILQ_CHECK_PREV(elm, field); \ if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ (elm)->field.tqe_prev; \ else { \ (head)->tqh_last = (elm)->field.tqe_prev; \ @@ -277,26 +822,20 @@ struct { \ } while (0) #define TAILQ_SWAP(head1, head2, type, field) do { \ - QUEUE_TYPEOF(type) * swap_first = (head1)->tqh_first; \ - QUEUE_TYPEOF(type) * *swap_last = (head1)->tqh_last; \ + QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ + QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ (head1)->tqh_first = (head2)->tqh_first; \ (head1)->tqh_last = (head2)->tqh_last; \ (head2)->tqh_first = swap_first; \ (head2)->tqh_last = swap_last; \ - swap_first = (head1)->tqh_first; \ - if (swap_first != NULL) \ + if ((swap_first = (head1)->tqh_first) != NULL) \ swap_first->field.tqe_prev = &(head1)->tqh_first; \ else \ (head1)->tqh_last = &(head1)->tqh_first; \ - swap_first = (head2)->tqh_first; \ - if (swap_first != NULL) \ + if ((swap_first = (head2)->tqh_first) != NULL) \ swap_first->field.tqe_prev = &(head2)->tqh_first; \ else \ (head2)->tqh_last = &(head2)->tqh_first; \ } while (0) -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_QUEUE_H_ */ +#endif /* !_SYS_QUEUE_H_ */ From patchwork Sun Apr 26 15:28:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Kozlyuk X-Patchwork-Id: 69347 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A7BFDA00C5; Sun, 26 Apr 2020 17:28:51 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 4886C1BF8E; Sun, 26 Apr 2020 17:28:39 +0200 (CEST) Received: from mail-lj1-f196.google.com (mail-lj1-f196.google.com [209.85.208.196]) by dpdk.org (Postfix) with ESMTP id 214A91BF76 for ; Sun, 26 Apr 2020 17:28:36 +0200 (CEST) Received: by mail-lj1-f196.google.com with SMTP id l19so14879650lje.10 for ; Sun, 26 Apr 2020 08:28:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=azDOlfmk1GQwE0ooSyeCwDczGhulza2iBFr3QlD7rt0=; b=k5WiCc+4lleUGvlxuKnEQrT0ufU+TtQARbo8tucoBKph4xqOkSRDezDWge2IPf5fCI tOzmgBH4Sz6dzOjmO/OQUcr6swz5jCLK5/r8RRfIWhKqiETb3nFgc+U8V27mVZJ3jD3y RZeBkmpJUSLHXPXFDYPkRo5UgPq5xPl5kVaoagB26QtF7sFX0vnJAuxSyWInf+1uN4cF BWpP80R+UWHwBhBSYF/tWCE3vA/bjrBuTzqOk4yyq7ep0A3BkjIP4p8g4kEWJddugmtk o9dfhZtFIEJRWjRNj+iPZ1HT7Xfp5K00KpGU/b6ECOtYsL9xSa4E9D0ye/bQKkdFU22K LLxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=azDOlfmk1GQwE0ooSyeCwDczGhulza2iBFr3QlD7rt0=; b=T0Th4MGEl1zI/9e0JDV+2MnMq4Tbp6H+TKzLlb8vkFc7P7q1jlXTsPpv7mADw2Pz3p +0WH+LW5wiMBBvcrb2W0iVwsD/qZCvZ5g+1dY4ZD7fTaGoclnRUMvDIbfjNiuQuwmftN MBeIrCvaME52eTE2Qf/1/gXuykoFabeUByrwxBOl1vGTPeWYA/qpDvc8fsHJA/G1/41W bQr+mBqFiIybIpmIK81IYPunP16UYUbY57L25m+sLJ5RHgC+FQTn63tmEotskjUbprJo 7hHQ3hVUqnLup1zie6rK0KsJSkQ1ghXBnUSKr2Qo5OVG3pP1adwLRaNceb8cSMDKa262 LzSQ== X-Gm-Message-State: AGi0PubisVn9SG4LlOwRf2ED6sPPBujO444Dfrx3hh5vk/c1O0KnXJn/ kxEtIO/eSl0923PTcQ9ZijImqw+a63s= X-Google-Smtp-Source: APiQypJddpBZ4HubTwSo0BdYuvwAHPLIPVIlsQYSlMSXxC5wf4HHeHde5VHuKEoB0r6lWppCMr7lGg== X-Received: by 2002:a2e:9456:: with SMTP id o22mr11774201ljh.94.1587914915274; Sun, 26 Apr 2020 08:28:35 -0700 (PDT) Received: from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru. [37.110.65.23]) by smtp.googlemail.com with ESMTPSA id p13sm8211340ljg.103.2020.04.26.08.28.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 26 Apr 2020 08:28:34 -0700 (PDT) From: Dmitry Kozlyuk To: dev@dpdk.org Cc: Pallavi Kadam , Narcisa Ana Maria Vasile , Ranjit Menon , Dmitry Kozlyuk , Jerin Jacob , Sunil Kumar Kori , Bruce Richardson Date: Sun, 26 Apr 2020 18:28:17 +0300 Message-Id: <20200426152819.2496610-3-dmitry.kozliuk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200426152819.2496610-1-dmitry.kozliuk@gmail.com> References: <20200426032245.2437733-1-dmitry.kozliuk@gmail.com> <20200426152819.2496610-1-dmitry.kozliuk@gmail.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" Add functions for handling directories in a platform-independent way: * eal_persistent_data_path() * eal_dir_create() Currently, only tracing requires this API for its common code. Signed-off-by: Dmitry Kozlyuk Acked-by: Narcisa Vasile --- .../common/eal_common_trace_utils.c | 26 +++------- lib/librte_eal/common/eal_filesystem.h | 30 ++++++++++- lib/librte_eal/freebsd/Makefile | 4 ++ lib/librte_eal/linux/Makefile | 4 ++ lib/librte_eal/meson.build | 4 ++ lib/librte_eal/unix/eal_unix_filesystem.c | 51 +++++++++++++++++++ lib/librte_eal/unix/meson.build | 6 +++ 7 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 lib/librte_eal/unix/eal_unix_filesystem.c create mode 100644 lib/librte_eal/unix/meson.build diff --git a/lib/librte_eal/common/eal_common_trace_utils.c b/lib/librte_eal/common/eal_common_trace_utils.c index fce8892c3..78df3b41e 100644 --- a/lib/librte_eal/common/eal_common_trace_utils.c +++ b/lib/librte_eal/common/eal_common_trace_utils.c @@ -3,8 +3,6 @@ */ #include -#include -#include #include #include @@ -321,22 +319,14 @@ trace_dir_default_path_get(char *dir_path) { struct trace *trace = trace_obj_get(); uint32_t size = sizeof(trace->dir); - struct passwd *pwd; - char *home_dir; - - /* First check for shell environment variable */ - home_dir = getenv("HOME"); - if (home_dir == NULL) { - /* Fallback to password file entry */ - pwd = getpwuid(getuid()); - if (pwd == NULL) - return -EINVAL; - - home_dir = pwd->pw_dir; - } + const char *perm_dir; + + perm_dir = eal_permanent_data_path(); + if (perm_dir == NULL) + return -EINVAL; /* Append dpdk-traces to directory */ - if (snprintf(dir_path, size, "%s/dpdk-traces/", home_dir) < 0) + if (snprintf(dir_path, size, "%s/dpdk-traces/", perm_dir) < 0) return -ENAMETOOLONG; return 0; @@ -371,7 +361,7 @@ trace_mkdir(void) } /* Create the path if it t exist, no "mkdir -p" available here */ - rc = mkdir(trace->dir, 0700); + rc = eal_dir_create(trace->dir); if (rc < 0 && errno != EEXIST) { trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno)); rte_errno = errno; @@ -385,7 +375,7 @@ trace_mkdir(void) if (rc < 0) return rc; - rc = mkdir(trace->dir, 0700); + rc = eal_dir_create(trace->dir); if (rc < 0) { trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno)); rte_errno = errno; diff --git a/lib/librte_eal/common/eal_filesystem.h b/lib/librte_eal/common/eal_filesystem.h index 5d21f07c2..77fe3be69 100644 --- a/lib/librte_eal/common/eal_filesystem.h +++ b/lib/librte_eal/common/eal_filesystem.h @@ -4,8 +4,8 @@ /** * @file - * Stores functions and path defines for files and directories - * on the filesystem for Linux, that are used by the Linux EAL. + * Stores functions and path defines for files and directories used by DPDK. + * Parts of this file are Unix-specific for historical reasons. */ #ifndef EAL_FILESYSTEM_H @@ -28,6 +28,32 @@ eal_create_runtime_dir(void); int eal_clean_runtime_dir(void); +/** + * Get absolute path to the directory where permanent data can be stored. + * + * @return + * Statically allocated string on success, NULL on failure. + */ +const char * +eal_permanent_data_path(void); + +/** + * Create a directory accessible to the current user only. + * + * This function does not create intermediate directories, + * thus only the last path component may be nonexistent. + * + * This function succeeds if path already exists and is a directory. + * + * Platform-independent code should use forward slash as path separator. + * + * @param path + * Path to be created. + * @return + * 0 on success, (-1) on failure and rte_errno is set. + */ +int eal_dir_create(const char *path); + /** Function to return hugefile prefix that's currently set up */ const char * eal_get_hugefile_prefix(void); diff --git a/lib/librte_eal/freebsd/Makefile b/lib/librte_eal/freebsd/Makefile index a8400f20a..5170a85ab 100644 --- a/lib/librte_eal/freebsd/Makefile +++ b/lib/librte_eal/freebsd/Makefile @@ -7,6 +7,7 @@ LIB = librte_eal.a ARCH_DIR ?= $(RTE_ARCH) VPATH += $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR) +VPATH += $(RTE_SDK)/lib/librte_eal/unix VPATH += $(RTE_SDK)/lib/librte_eal/common CFLAGS += -I$(SRCDIR)/include @@ -74,6 +75,9 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_service.c SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_random.c SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_reciprocal.c +# from unix dir +SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_unix_filesystem.c + # from arch dir SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_cpuflags.c SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_hypervisor.c diff --git a/lib/librte_eal/linux/Makefile b/lib/librte_eal/linux/Makefile index a77eb1757..bdbcb9801 100644 --- a/lib/librte_eal/linux/Makefile +++ b/lib/librte_eal/linux/Makefile @@ -7,6 +7,7 @@ LIB = librte_eal.a ARCH_DIR ?= $(RTE_ARCH) VPATH += $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR) +VPATH += $(RTE_SDK)/lib/librte_eal/unix VPATH += $(RTE_SDK)/lib/librte_eal/common CFLAGS += -I$(SRCDIR)/include @@ -81,6 +82,9 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_service.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_random.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_reciprocal.c +# from unix dir +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_unix_filesystem.c + # from arch dir SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_cpuflags.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_hypervisor.c diff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build index 0267c3b9d..98c97dd07 100644 --- a/lib/librte_eal/meson.build +++ b/lib/librte_eal/meson.build @@ -6,6 +6,10 @@ subdir('include') subdir('common') +if not is_windows + subdir('unix') +endif + dpdk_conf.set('RTE_EXEC_ENV_' + exec_env.to_upper(), 1) subdir(exec_env) diff --git a/lib/librte_eal/unix/eal_unix_filesystem.c b/lib/librte_eal/unix/eal_unix_filesystem.c new file mode 100644 index 000000000..f5a64eecc --- /dev/null +++ b/lib/librte_eal/unix/eal_unix_filesystem.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2020 Dmitry Kozlyuk + */ + +#include + +#include +#include +#include + +#include + +#include + +const char * +eal_permanent_data_path(void) +{ + static char path[PATH_MAX]; /* static so auto-zeroed */ + + const char *home_dir; + struct passwd *pwd; + + if (path[0] != '\0') + return path; + + /* First check for shell environment variable */ + home_dir = getenv("HOME"); + if (home_dir == NULL) { + /* Fallback to password file entry */ + pwd = getpwuid(getuid()); + if (pwd == NULL) + return NULL; + + home_dir = pwd->pw_dir; + } + + if (strlen(home_dir) >= sizeof(path)) + return NULL; + + strncpy(path, home_dir, sizeof(path)); + return path; +} + +int +eal_dir_create(const char *path) +{ + int ret = mkdir(path, 0700); + if (ret) + rte_errno = errno; + return ret; +} diff --git a/lib/librte_eal/unix/meson.build b/lib/librte_eal/unix/meson.build new file mode 100644 index 000000000..fafa41685 --- /dev/null +++ b/lib/librte_eal/unix/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2020 Dmitry Kozlyuk + +sources += files( + 'eal_unix_filesystem.c', +) From patchwork Sun Apr 26 15:28:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Kozlyuk X-Patchwork-Id: 69348 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id F2FC2A00C5; Sun, 26 Apr 2020 17:29:02 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 159111C010; Sun, 26 Apr 2020 17:28:42 +0200 (CEST) Received: from mail-lj1-f193.google.com (mail-lj1-f193.google.com [209.85.208.193]) by dpdk.org (Postfix) with ESMTP id CB5271BF81 for ; Sun, 26 Apr 2020 17:28:37 +0200 (CEST) Received: by mail-lj1-f193.google.com with SMTP id u15so14907342ljd.3 for ; Sun, 26 Apr 2020 08:28:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bDeuWB7xKeR56AjalduIYXgeJhsnIy+CUOzOqKtBgm4=; b=NFgI/fYixDlDq98CLbOq7Tc/zZ8cSSaXUbDTD7HRHuNm/g9WYl5IpUUxCc28KCIoyB wfzQOlm5Ok4gEXmF8Aw1GH8xU6dbK4Oe9ZAycM16q2GopXu5FuCeARdOkF95uCj291Wj S9rrJusP9a+j0xr8KNEG2aM5gwODlQCwOF/hpUfs2ySvck3TFuz8GoQDwTl2YjkzAQjX Ye6v+/uAyOZOXJCaueM0OhsJ982W6MKGPrFzbdigWd9LIeAl+oWThjhYEnee7wnRj0TZ GTwhnZ5XIsVzQ93lP39srYhOeAZZjNS5y0KbO6l8eq5ZHZz34yY/GQ/f3NRuf/Bshgoa ZncA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bDeuWB7xKeR56AjalduIYXgeJhsnIy+CUOzOqKtBgm4=; b=FtjW9fRaa1CfPxGj5EadJl+8HD8JxI12Zt8hBS4dSlV3pezJSueIdvsYvLC12wWsAZ NnTC8XH3B9NuyeTTeX6ZO/D4AdNG8yogXf/lIph+YAj8Nl+ssDk7l7dXmcifJBoALPxl hh1rK9+BinozL+JNXQ2gEdZjOU3FQ4TuGgSjl7Zjaqwd+/q8yhWlDxoWEQIOYlGHtjNX HJSJ1fjwdRitCMLnuTNUY/3Xs/y0IpSmw93n10K5A0e3lXFK6XHR26+WLUtWZ00no2Ro Zn5m2O+9/ch2C3BZb9CHcjm1fNHDghOFaziCBPKTHtth1G/DLmrl4YjVPwvDKkyYKO9s Yeew== X-Gm-Message-State: AGi0PuZRkxXhQCKkIimmYiXbDVif4ULdlHxZpfpF+TdY08LegSPRxTUK 7tUuXM8e/Zd1EEYsLEFwj5X1vETY2Lk= X-Google-Smtp-Source: APiQypLdzSYaUIOpKVYvBQczMvxfbGT+aA4uKqR3rsgPl3KkMzeY+acnwF7hrA+767lAdjsOapdFJQ== X-Received: by 2002:a2e:5813:: with SMTP id m19mr3661142ljb.230.1587914916956; Sun, 26 Apr 2020 08:28:36 -0700 (PDT) Received: from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru. [37.110.65.23]) by smtp.googlemail.com with ESMTPSA id p13sm8211340ljg.103.2020.04.26.08.28.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 26 Apr 2020 08:28:36 -0700 (PDT) From: Dmitry Kozlyuk To: dev@dpdk.org Cc: Pallavi Kadam , Narcisa Ana Maria Vasile , Ranjit Menon , Dmitry Kozlyuk , Thomas Monjalon , Jerin Jacob , Sunil Kumar Kori , Harini Ramakrishnan , Omar Cardona , David Marchand Date: Sun, 26 Apr 2020 18:28:18 +0300 Message-Id: <20200426152819.2496610-4-dmitry.kozliuk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200426152819.2496610-1-dmitry.kozliuk@gmail.com> References: <20200426032245.2437733-1-dmitry.kozliuk@gmail.com> <20200426152819.2496610-1-dmitry.kozliuk@gmail.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 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" Replace clock_gettime(CLOCK_REALTIME) with C11 timespec_get(). Implementation is provided for MinGW-w64 that misses this function. Provide minimum viable implementations of malloc and timer functions used by tracing. Regex stubs are already present in Windows EAL. Fixes: 185b7dc1d467 ("trace: save bootup timestamp") Fixes: 321dd5f8fa62 ("trace: add internal init and fini interface") Reported-by: Pallavi Kadam Signed-off-by: Dmitry Kozlyuk --- config/meson.build | 2 + .../common/eal_common_trace_utils.c | 3 +- lib/librte_eal/common/meson.build | 5 + .../include/generic/rte_byteorder.h | 4 +- lib/librte_eal/windows/eal.c | 92 +++++++++++++++++++ lib/librte_eal/windows/eal_thread.c | 9 ++ lib/librte_eal/windows/eal_windows.h | 3 + lib/librte_eal/windows/include/rte_os.h | 33 +++++-- 8 files changed, 141 insertions(+), 10 deletions(-) diff --git a/config/meson.build b/config/meson.build index e851b407b..91cba9313 100644 --- a/config/meson.build +++ b/config/meson.build @@ -267,6 +267,8 @@ if is_windows # Minimum supported API is Windows 7. add_project_arguments('-D_WIN32_WINNT=0x0601', language: 'c') + add_project_link_arguments(['-lshell32', '-lshlwapi'], language: 'c') + # Use MinGW-w64 stdio, because DPDK assumes ANSI-compliant formatting. if cc.get_id() == 'gcc' add_project_arguments('-D__USE_MINGW_ANSI_STDIO', language: 'c') diff --git a/lib/librte_eal/common/eal_common_trace_utils.c b/lib/librte_eal/common/eal_common_trace_utils.c index 78df3b41e..1fb5bc772 100644 --- a/lib/librte_eal/common/eal_common_trace_utils.c +++ b/lib/librte_eal/common/eal_common_trace_utils.c @@ -7,6 +7,7 @@ #include #include +#include #include #include "eal_filesystem.h" @@ -300,7 +301,7 @@ trace_epoch_time_save(void) uint64_t avg, start, end; start = rte_get_tsc_cycles(); - if (clock_gettime(CLOCK_REALTIME, &epoch) < 0) { + if (timespec_get(&epoch, TIME_UTC) < 0) { trace_err("failed to get the epoch time"); return -1; } diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build index 155da29b4..f7393b8c3 100644 --- a/lib/librte_eal/common/meson.build +++ b/lib/librte_eal/common/meson.build @@ -14,6 +14,11 @@ if is_windows 'eal_common_log.c', 'eal_common_options.c', 'eal_common_thread.c', + 'eal_common_trace.c', + 'eal_common_trace_ctf.c', + 'eal_common_trace_utils.c', + 'eal_common_string_fns.c', + 'eal_common_uuid.c', 'rte_option.c', ) subdir_done() diff --git a/lib/librte_eal/include/generic/rte_byteorder.h b/lib/librte_eal/include/generic/rte_byteorder.h index 38e8cfd32..bc3ad8e23 100644 --- a/lib/librte_eal/include/generic/rte_byteorder.h +++ b/lib/librte_eal/include/generic/rte_byteorder.h @@ -15,9 +15,9 @@ */ #include -#ifdef RTE_EXEC_ENV_FREEBSD +#if defined(RTE_EXEC_ENV_FREEBSD) #include -#else +#elif defined(RTE_EXEC_ENV_LINUX) #include #endif diff --git a/lib/librte_eal/windows/eal.c b/lib/librte_eal/windows/eal.c index 2cf7a04ef..fec7e5001 100644 --- a/lib/librte_eal/windows/eal.c +++ b/lib/librte_eal/windows/eal.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "eal_windows.h" @@ -208,6 +209,91 @@ eal_parse_args(int argc, char **argv) return ret; } +void * +eal_malloc_no_trace(const char *type, size_t size, unsigned int align) +{ + /* Simulate failure, so that tracing falls back to malloc(). */ + RTE_SET_USED(type); + RTE_SET_USED(size); + RTE_SET_USED(align); + return NULL; +} + +void +eal_free_no_trace(void *addr __rte_unused) +{ + /* Nothing to free. */ +} + +/* MinGW-w64 does not implement timespec_get(). */ +#ifdef RTE_TOOLCHAIN_GCC + +int +timespec_get(struct timespec *ts, int base) +{ + static const uint64_t UNITS_PER_SEC = 10000000; /* 1 unit = 100 ns */ + + FILETIME ft; + ULARGE_INTEGER ui; + + GetSystemTimePreciseAsFileTime(&ft); + ui.LowPart = ft.dwLowDateTime; + ui.HighPart = ft.dwHighDateTime; + ts->tv_sec = ui.QuadPart / UNITS_PER_SEC; + ts->tv_nsec = ui.QuadPart - (ts->tv_sec * UNITS_PER_SEC); + return base; +} + +#endif /* RTE_TOOLCHAIN_GCC */ + +uint64_t +rte_get_tsc_hz(void) +{ + static LARGE_INTEGER freq; /* static so auto-zeroed */ + + if (freq.QuadPart != 0) + return freq.QuadPart; + + QueryPerformanceFrequency(&freq); + return freq.QuadPart; +} + +const char * +eal_permanent_data_path(void) +{ + static char buffer[PATH_MAX]; /* static so auto-zeroed */ + + HRESULT ret; + + if (buffer[0] != '\0') + return buffer; + + ret = SHGetFolderPathA( + NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, buffer); + if (FAILED(ret)) { + RTE_LOG_WIN32_ERR("SHGetFolderPathA(CSIDL_LOCAL_APPDATA)"); + return NULL; + } + + return buffer; +} + +int +eal_dir_create(const char *path) +{ + /* CreateDirectoryA() fails if directory exists. */ + if (PathIsDirectoryA(path)) + return 0; + + /* Default ACL already restricts access to creator and owner only. */ + if (!CreateDirectoryA(path, NULL)) { + RTE_LOG_WIN32_ERR("CreateDirectoryA(\"%s\", NULL)", path); + rte_errno = EINVAL; + return -1; + } + return 0; +} + static int sync_func(void *arg __rte_unused) { @@ -242,6 +328,12 @@ rte_eal_init(int argc, char **argv) if (fctret < 0) exit(1); + if (eal_trace_init() < 0) { + rte_eal_init_alert("Cannot init trace"); + rte_errno = EFAULT; + return -1; + } + eal_thread_init_master(rte_config.master_lcore); RTE_LCORE_FOREACH_SLAVE(i) { diff --git a/lib/librte_eal/windows/eal_thread.c b/lib/librte_eal/windows/eal_thread.c index e149199a6..9feb2bfd0 100644 --- a/lib/librte_eal/windows/eal_thread.c +++ b/lib/librte_eal/windows/eal_thread.c @@ -157,6 +157,15 @@ eal_thread_create(pthread_t *thread) return 0; } +int +rte_thread_getname(pthread_t id, char *name, size_t len) +{ + RTE_SET_USED(id); + RTE_SET_USED(name); + RTE_SET_USED(len); + return -ENOTSUP; +} + int rte_thread_setname(__rte_unused pthread_t id, __rte_unused const char *name) { diff --git a/lib/librte_eal/windows/eal_windows.h b/lib/librte_eal/windows/eal_windows.h index fadd676b2..f259fdc53 100644 --- a/lib/librte_eal/windows/eal_windows.h +++ b/lib/librte_eal/windows/eal_windows.h @@ -11,6 +11,9 @@ #include +#include +#include + /** * Create a map of processors and cores on the system. */ diff --git a/lib/librte_eal/windows/include/rte_os.h b/lib/librte_eal/windows/include/rte_os.h index 510e39e03..6f4333eb5 100644 --- a/lib/librte_eal/windows/include/rte_os.h +++ b/lib/librte_eal/windows/include/rte_os.h @@ -46,15 +46,13 @@ extern "C" { typedef long long ssize_t; #ifndef RTE_TOOLCHAIN_GCC + static inline int -asprintf(char **buffer, const char *format, ...) +vasprintf(char **buffer, const char *format, va_list arg) { int size, ret; - va_list arg; - va_start(arg, format); size = vsnprintf(NULL, 0, format, arg); - va_end(arg); if (size < 0) return -1; size++; @@ -63,16 +61,37 @@ asprintf(char **buffer, const char *format, ...) if (*buffer == NULL) return -1; - va_start(arg, format); ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); if (ret != size - 1) { free(*buffer); return -1; } return ret; } -#endif /* RTE_TOOLCHAIN_GCC */ + +static inline int +asprintf(char **buffer, const char *format, ...) +{ + int ret; + va_list arg; + + va_start(arg, format); + ret = vasprintf(buffer, format, arg); + va_end(arg); + + return ret; +} + +#else /* RTE_TOOLCHAIN_GCC */ + +/* value as in time.h from UCRT */ +#define TIME_UTC 1 + +struct timespec; + +int timespec_get(struct timespec *ts, int base); + +#endif /* !RTE_TOOLCHAIN_GCC */ #ifdef __cplusplus }