* [dpdk-dev] [PATCH 0/2] eal/windows: fix build by supporing trace
@ 2020-04-26 3:22 Dmitry Kozlyuk
2020-04-26 3:22 ` [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 3:22 UTC (permalink / raw)
To: dev; +Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon, Dmitry Kozlyuk
This patch fixes errors caused by using Unix-only functions in tracing
EAL. It introduces new internal EAL wrappers for directory management
and provides simple, but correct implementation for some EAL functions
required for tracing.
This patch implements rte_get_tsc_hz() instead of basing upon a pending
patchset, because fixing the build allows testing said patchset in the
first place, and also re-implemented code is only a few lines.
Dmitry Kozlyuk (2):
eal/windows: replace sys/queue.h with a complete one from FreeBSD
eal/windows: fix build by supporting trace
config/meson.build | 2 +
.../common/eal_common_trace_utils.c | 29 +-
lib/librte_eal/common/eal_private.h | 26 +
lib/librte_eal/common/meson.build | 5 +
lib/librte_eal/freebsd/Makefile | 4 +
.../include/generic/rte_byteorder.h | 4 +-
lib/librte_eal/linux/Makefile | 4 +
lib/librte_eal/meson.build | 4 +
lib/librte_eal/unix/eal_unix.c | 45 ++
lib/librte_eal/unix/meson.build | 6 +
lib/librte_eal/windows/eal.c | 91 +++
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 +-
lib/librte_eal/windows/include/sys/queue.h | 663 ++++++++++++++++--
15 files changed, 838 insertions(+), 90 deletions(-)
create mode 100644 lib/librte_eal/unix/eal_unix.c
create mode 100644 lib/librte_eal/unix/meson.build
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD
2020-04-26 3:22 [dpdk-dev] [PATCH 0/2] eal/windows: fix build by supporing trace Dmitry Kozlyuk
@ 2020-04-26 3:22 ` Dmitry Kozlyuk
2020-04-26 11:14 ` Jerin Jacob
2020-04-26 3:22 ` [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2 siblings, 1 reply; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 3:22 UTC (permalink / raw)
To: dev
Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Harini Ramakrishnan, Omar Cardona, Jerin Jacob,
David Marchand, Sunil Kumar Kori
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.
Fixes: 321dd5f8fa62 ("trace: add internal init and fini interface")
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
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_ */
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace
2020-04-26 3:22 [dpdk-dev] [PATCH 0/2] eal/windows: fix build by supporing trace Dmitry Kozlyuk
2020-04-26 3:22 ` [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
@ 2020-04-26 3:22 ` Dmitry Kozlyuk
2020-04-26 11:32 ` Jerin Jacob
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2 siblings, 1 reply; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 3:22 UTC (permalink / raw)
To: dev
Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Thomas Monjalon, Jerin Jacob, Sunil Kumar Kori,
Bruce Richardson, Harini Ramakrishnan, Omar Cardona,
David Marchand
Add EAL private functions to support trace storage:
* eal_persistent_data_path()
* eal_dir_create()
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.
Fixes: 185b7dc1d467 ("trace: save bootup timestamp")
Fixes: 321dd5f8fa62 ("trace: add internal init and fini interface")
Reported-by: Pallavi Kadam <pallavi.kadam@intel.com>
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
config/meson.build | 2 +
.../common/eal_common_trace_utils.c | 29 ++----
lib/librte_eal/common/eal_private.h | 26 ++++++
lib/librte_eal/common/meson.build | 5 +
lib/librte_eal/freebsd/Makefile | 4 +
.../include/generic/rte_byteorder.h | 4 +-
lib/librte_eal/linux/Makefile | 4 +
lib/librte_eal/meson.build | 4 +
lib/librte_eal/unix/eal_unix.c | 45 +++++++++
lib/librte_eal/unix/meson.build | 6 ++
lib/librte_eal/windows/eal.c | 91 +++++++++++++++++++
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 +++++--
14 files changed, 237 insertions(+), 28 deletions(-)
create mode 100644 lib/librte_eal/unix/eal_unix.c
create mode 100644 lib/librte_eal/unix/meson.build
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 fce8892c3..1fb5bc772 100644
--- a/lib/librte_eal/common/eal_common_trace_utils.c
+++ b/lib/librte_eal/common/eal_common_trace_utils.c
@@ -3,12 +3,11 @@
*/
#include <fnmatch.h>
-#include <pwd.h>
-#include <sys/stat.h>
#include <time.h>
#include <rte_common.h>
#include <rte_errno.h>
+#include <rte_os.h>
#include <rte_string_fns.h>
#include "eal_filesystem.h"
@@ -302,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;
}
@@ -321,22 +320,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 +362,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 +376,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_private.h b/lib/librte_eal/common/eal_private.h
index ecf827914..b3504e484 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -448,4 +448,30 @@ eal_malloc_no_trace(const char *type, size_t size, unsigned int align);
void eal_free_no_trace(void *addr);
+/**
+ * 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);
+
#endif /* _EAL_PRIVATE_H_ */
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/freebsd/Makefile b/lib/librte_eal/freebsd/Makefile
index a8400f20a..a26c455c7 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.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/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 <stdint.h>
-#ifdef RTE_EXEC_ENV_FREEBSD
+#if defined(RTE_EXEC_ENV_FREEBSD)
#include <sys/endian.h>
-#else
+#elif defined(RTE_EXEC_ENV_LINUX)
#include <endian.h>
#endif
diff --git a/lib/librte_eal/linux/Makefile b/lib/librte_eal/linux/Makefile
index a77eb1757..fa41f00bf 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.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.c b/lib/librte_eal/unix/eal_unix.c
new file mode 100644
index 000000000..dc0ade2f3
--- /dev/null
+++ b/lib/librte_eal/unix/eal_unix.c
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2020 Dmitry Kozlyuk
+ */
+
+#include <stdlib.h>
+
+#include <pwd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rte_errno.h>
+
+#include <eal_private.h>
+
+const char *
+eal_permanent_data_path(void)
+{
+ static const char *home_dir; /* static so auto-zeroed */
+
+ struct passwd *pwd;
+
+ if (home_dir != NULL)
+ return 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 NULL;
+
+ home_dir = pwd->pw_dir;
+ }
+ return home_dir;
+}
+
+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..812273fc9
--- /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.c',
+)
diff --git a/lib/librte_eal/windows/eal.c b/lib/librte_eal/windows/eal.c
index 2cf7a04ef..028413b5e 100644
--- a/lib/librte_eal/windows/eal.c
+++ b/lib/librte_eal/windows/eal.c
@@ -17,6 +17,7 @@
#include <eal_filesystem.h>
#include <eal_options.h>
#include <eal_private.h>
+#include <eal_trace.h>
#include "eal_windows.h"
@@ -208,6 +209,90 @@ 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[MAX_PATH]; /* 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 +327,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 <rte_windows.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+
/**
* 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
}
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD
2020-04-26 3:22 ` [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
@ 2020-04-26 11:14 ` Jerin Jacob
0 siblings, 0 replies; 19+ messages in thread
From: Jerin Jacob @ 2020-04-26 11:14 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Harini Ramakrishnan, Omar Cardona, Jerin Jacob, David Marchand,
Sunil Kumar Kori
On Sun, Apr 26, 2020 at 8:53 AM Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote:
>
> 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.
>
> Fixes: 321dd5f8fa62 ("trace: add internal init and fini interface")
IMO, we don't need to mark this patch as fixes.
> Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
> ---
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace
2020-04-26 3:22 ` [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace Dmitry Kozlyuk
@ 2020-04-26 11:32 ` Jerin Jacob
2020-04-26 12:02 ` Dmitry Kozlyuk
0 siblings, 1 reply; 19+ messages in thread
From: Jerin Jacob @ 2020-04-26 11:32 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Thomas Monjalon, Jerin Jacob, Sunil Kumar Kori, Bruce Richardson,
Harini Ramakrishnan, Omar Cardona, David Marchand
On Sun, Apr 26, 2020 at 8:53 AM Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote:
>
> Add EAL private functions to support trace storage:
>
> * eal_persistent_data_path()
> * eal_dir_create()
>
> 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.
>
> Fixes: 185b7dc1d467 ("trace: save bootup timestamp")
> Fixes: 321dd5f8fa62 ("trace: add internal init and fini interface")
> Reported-by: Pallavi Kadam <pallavi.kadam@intel.com>
> Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
> ---
In general, the patch looks good to me. Could you split the patch as two
1) New eal_permanent_data_path() and eal_dir_create() API definition,
and its implementation with unix and the common code changes to adapt new APIs.
2) Windows implementation of eal_permanent_data_path() and other
missing pieces for
trace implementation.
Some comments below,
>
> void eal_free_no_trace(void *addr);
>
> +/**
> + * 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);
Do windows have PATH_MAX kind of macro? I think, it is better API
consumer allocates
the memory of size PATH_MAX and implementation fills it, instead of,
the static scheme.
> +
> +/**
> + * 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);
>
Looks good to me.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace
2020-04-26 11:32 ` Jerin Jacob
@ 2020-04-26 12:02 ` Dmitry Kozlyuk
2020-04-26 12:23 ` Jerin Jacob
0 siblings, 1 reply; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 12:02 UTC (permalink / raw)
To: Jerin Jacob
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Thomas Monjalon, Jerin Jacob, Sunil Kumar Kori, Bruce Richardson,
Harini Ramakrishnan, Omar Cardona, David Marchand
On 2020-04-26 17:02 GMT+0530 Jerin Jacob wrote:
> > +/**
> > + * 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);
>
> Do windows have PATH_MAX kind of macro? I think, it is better API
> consumer allocates
> the memory of size PATH_MAX and implementation fills it, instead of,
> the static scheme.
This API falls in line with rte_eal_get_runtime_dir() and other
eal_filesystem.h functions, that use static scheme. Logically, its result
never changes. It is race-free and is only called during initialization. What
you propose can be done, but are there any benefits?
While we're at it, don't these declarations belong to eal_filesystem.h? I
left them in eal_private.h, because eal_filesystem.h is mostly Unix-specific.
--
Dmitry Kozlyuk
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace
2020-04-26 12:02 ` Dmitry Kozlyuk
@ 2020-04-26 12:23 ` Jerin Jacob
2020-04-26 12:36 ` Thomas Monjalon
2020-04-26 12:50 ` Dmitry Kozlyuk
0 siblings, 2 replies; 19+ messages in thread
From: Jerin Jacob @ 2020-04-26 12:23 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Thomas Monjalon, Jerin Jacob, Sunil Kumar Kori, Bruce Richardson,
Harini Ramakrishnan, Omar Cardona, David Marchand
On Sun, Apr 26, 2020 at 5:32 PM Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote:
>
> On 2020-04-26 17:02 GMT+0530 Jerin Jacob wrote:
> > > +/**
> > > + * 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);
> >
> > Do windows have PATH_MAX kind of macro? I think, it is better API
> > consumer allocates
> > the memory of size PATH_MAX and implementation fills it, instead of,
> > the static scheme.
>
> This API falls in line with rte_eal_get_runtime_dir() and other
> eal_filesystem.h functions, that use static scheme. Logically, its result
> never changes. It is race-free and is only called during initialization. What
> you propose can be done, but are there any benefits?
I thought who will free that memory? It looks like libc creating a static memory
for this item. so, your current eal_permanent_data_path() declarations
looks good to
me.
>
> While we're at it, don't these declarations belong to eal_filesystem.h? I
> left them in eal_private.h, because eal_filesystem.h is mostly Unix-specific.
Understood, Leaving that decision to EAL maintainers.
>
> --
> Dmitry Kozlyuk
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace
2020-04-26 12:23 ` Jerin Jacob
@ 2020-04-26 12:36 ` Thomas Monjalon
2020-04-26 12:50 ` Dmitry Kozlyuk
1 sibling, 0 replies; 19+ messages in thread
From: Thomas Monjalon @ 2020-04-26 12:36 UTC (permalink / raw)
To: Dmitry Kozlyuk, Jerin Jacob
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Jerin Jacob, Sunil Kumar Kori, Bruce Richardson,
Harini Ramakrishnan, Omar Cardona, David Marchand
26/04/2020 14:23, Jerin Jacob:
> On Sun, Apr 26, 2020 at 5:32 PM Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote:
> > While we're at it, don't these declarations belong to eal_filesystem.h? I
> > left them in eal_private.h, because eal_filesystem.h is mostly Unix-specific.
Yes it looks to be a good fit for eal_filesystem.h.
Don't hesitate removing Linux specifics (starting with the file comment).
> Understood, Leaving that decision to EAL maintainers.
There is no EAL maintainer for this.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace
2020-04-26 12:23 ` Jerin Jacob
2020-04-26 12:36 ` Thomas Monjalon
@ 2020-04-26 12:50 ` Dmitry Kozlyuk
1 sibling, 0 replies; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 12:50 UTC (permalink / raw)
To: Jerin Jacob
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Thomas Monjalon, Jerin Jacob, Sunil Kumar Kori, Bruce Richardson,
Harini Ramakrishnan, Omar Cardona, David Marchand
On 2020-04-26 17:53 GMT+0530 Jerin Jacob wrote:
> On Sun, Apr 26, 2020 at 5:32 PM Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote:
> >
> > On 2020-04-26 17:02 GMT+0530 Jerin Jacob wrote:
> > > > +/**
> > > > + * 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);
> > >
> > > Do windows have PATH_MAX kind of macro? I think, it is better API
> > > consumer allocates
> > > the memory of size PATH_MAX and implementation fills it, instead of,
> > > the static scheme.
> >
> > This API falls in line with rte_eal_get_runtime_dir() and other
> > eal_filesystem.h functions, that use static scheme. Logically, its result
> > never changes. It is race-free and is only called during initialization. What
> > you propose can be done, but are there any benefits?
>
> I thought who will free that memory? It looks like libc creating a static memory
> for this item. so, your current eal_permanent_data_path() declarations
> looks good to
> me.
Actually, your concern is valid (see man quotes below). Windows implementation
has no such issue because of its own static buffer. I'd use static scheme
in EAL interface for convenience, but change Unix implementation to copy
string returned by libc into a static buffer.
man 3 getenv:
The string pointed to by the return value of getenv() may be
statically allocated, and can be modified by a subsequent call to
getenv(), putenv(3), setenv(3), or unsetenv(3).
man 3 getpwuid:
The return value may point to a static area, and may be overwritten
by subsequent calls to getpwent(3), getpwnam(), or getpwuid().
--
Dmitry Kozlyuk
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation
2020-04-26 3:22 [dpdk-dev] [PATCH 0/2] eal/windows: fix build by supporing trace Dmitry Kozlyuk
2020-04-26 3:22 ` [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
2020-04-26 3:22 ` [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace Dmitry Kozlyuk
@ 2020-04-26 15:28 ` Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 1/3] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
` (3 more replies)
2 siblings, 4 replies; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 15:28 UTC (permalink / raw)
To: dev; +Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon, Dmitry Kozlyuk
This patch fixes errors caused by using Unix-only functions in tracing
EAL. It does not provide full tracing support for Windows because of
missing regex implementation. It introduces new internal EAL wrappers
for directory management and provides basic, but correct implementation
for some EAL functions required for tracing compilation.
This patch implements rte_get_tsc_hz() instead of basing upon a pending
patchset, because fixing the build allows testing said patchset in the
first place, and also re-implemented code is only a few lines.
v2:
* Change title to reflect that only tracing compilation is enabled.
* Split commits adding new API and fixind build on Windows.
* Move new functions to eal_filesystem.h.
* Remove unneeded Fixes: line.
Dmitry Kozlyuk (3):
eal/windows: replace sys/queue.h with a complete one from FreeBSD
eal: add internal directory management API
eal/windows: fix build by enabling trace compilation
config/meson.build | 2 +
.../common/eal_common_trace_utils.c | 29 +-
lib/librte_eal/common/eal_filesystem.h | 30 +-
lib/librte_eal/common/meson.build | 5 +
lib/librte_eal/freebsd/Makefile | 4 +
.../include/generic/rte_byteorder.h | 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 +
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 +-
lib/librte_eal/windows/include/sys/queue.h | 663 ++++++++++++++++--
15 files changed, 847 insertions(+), 92 deletions(-)
create mode 100644 lib/librte_eal/unix/eal_unix_filesystem.c
create mode 100644 lib/librte_eal/unix/meson.build
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH v2 1/3] eal/windows: replace sys/queue.h with a complete one from FreeBSD
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
@ 2020-04-26 15:28 ` Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API Dmitry Kozlyuk
` (2 subsequent siblings)
3 siblings, 0 replies; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 15:28 UTC (permalink / raw)
To: dev
Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Harini Ramakrishnan, Omar Cardona
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 <dmitry.kozliuk@gmail.com>
---
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_ */
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 1/3] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
@ 2020-04-26 15:28 ` Dmitry Kozlyuk
2020-05-04 20:14 ` Narcisa Ana Maria Vasile
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2020-04-26 16:41 ` [dpdk-dev] [PATCH v3] eal: disable tracing on Windows Dmitry Kozlyuk
3 siblings, 1 reply; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 15:28 UTC (permalink / raw)
To: dev
Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Jerin Jacob, Sunil Kumar Kori, Bruce Richardson
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 <dmitry.kozliuk@gmail.com>
---
.../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 <fnmatch.h>
-#include <pwd.h>
-#include <sys/stat.h>
#include <time.h>
#include <rte_common.h>
@@ -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 <stdlib.h>
+
+#include <pwd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rte_errno.h>
+
+#include <eal_filesystem.h>
+
+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',
+)
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 1/3] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API Dmitry Kozlyuk
@ 2020-04-26 15:28 ` Dmitry Kozlyuk
2020-04-26 15:38 ` Thomas Monjalon
2020-04-26 16:41 ` [dpdk-dev] [PATCH v3] eal: disable tracing on Windows Dmitry Kozlyuk
3 siblings, 1 reply; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 15:28 UTC (permalink / raw)
To: dev
Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Thomas Monjalon, Jerin Jacob, Sunil Kumar Kori,
Harini Ramakrishnan, Omar Cardona, David Marchand
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 <pallavi.kadam@intel.com>
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
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 <rte_common.h>
#include <rte_errno.h>
+#include <rte_os.h>
#include <rte_string_fns.h>
#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 <stdint.h>
-#ifdef RTE_EXEC_ENV_FREEBSD
+#if defined(RTE_EXEC_ENV_FREEBSD)
#include <sys/endian.h>
-#else
+#elif defined(RTE_EXEC_ENV_LINUX)
#include <endian.h>
#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 <eal_filesystem.h>
#include <eal_options.h>
#include <eal_private.h>
+#include <eal_trace.h>
#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 <rte_windows.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+
/**
* 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
}
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
@ 2020-04-26 15:38 ` Thomas Monjalon
2020-04-26 16:42 ` Dmitry Kozlyuk
0 siblings, 1 reply; 19+ messages in thread
From: Thomas Monjalon @ 2020-04-26 15:38 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Jerin Jacob, Sunil Kumar Kori,
Harini Ramakrishnan, Omar Cardona, David Marchand
I think this patch is doing too many things at once.
Why not just disabling tracing on Windows for now,
and apply proper patches for memory management, timer, endianness, etc
in 20.08?
Some cosmetic comments below,
26/04/2020 17:28, Dmitry Kozlyuk:
> 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 <pallavi.kadam@intel.com>
> Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
Blank line is required between "Fixes" block and " Reported/SoB".
[...]
> --- a/lib/librte_eal/include/generic/rte_byteorder.h
> +++ b/lib/librte_eal/include/generic/rte_byteorder.h
> -#ifdef RTE_EXEC_ENV_FREEBSD
> +#if defined(RTE_EXEC_ENV_FREEBSD)
No need to change above line.
> #include <sys/endian.h>
> -#else
> +#elif defined(RTE_EXEC_ENV_LINUX)
Parenthesis are useless.
> #include <endian.h>
> #endif
^ permalink raw reply [flat|nested] 19+ messages in thread
* [dpdk-dev] [PATCH v3] eal: disable tracing on Windows
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
` (2 preceding siblings ...)
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
@ 2020-04-26 16:41 ` Dmitry Kozlyuk
2020-04-26 17:46 ` Jerin Jacob
3 siblings, 1 reply; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 16:41 UTC (permalink / raw)
To: dev
Cc: Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Dmitry Kozlyuk, Thomas Monjalon, Sunil Kumar Kori,
David Marchand, Jerin Jacob
Fix build errors caused by using Unix-specific functions in common code.
Hide and disable command-line options related to tracing on Windows.
Fixes: 3d26a70ae338 ("trace: add trace configuration parameter")
Fixes: 3b155d24bdaf ("trace: hook subsystem to Linux")
Reported-by: Pallavi Kadam <pallavi.kadam@intel.com>
Suggested-by: Thomas Monjalon <thomas@monjalon.net>
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
lib/librte_eal/common/eal_common_options.c | 6 ++++++
lib/librte_eal/common/eal_common_thread.c | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index 7e3a7df9c..418731ca4 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -34,7 +34,9 @@
#include "eal_options.h"
#include "eal_filesystem.h"
#include "eal_private.h"
+#ifndef RTE_EXEC_ENV_WINDOWS
#include "eal_trace.h"
+#endif
#define BITS_PER_HEX 4
#define LCORE_OPT_LST 1
@@ -1424,6 +1426,7 @@ eal_parse_common_option(int opt, const char *optarg,
break;
}
+#ifndef RTE_EXEC_ENV_WINDOWS
case OPT_TRACE_NUM: {
if (eal_trace_args_save(optarg) < 0) {
RTE_LOG(ERR, EAL, "invalid parameters for --"
@@ -1459,6 +1462,7 @@ eal_parse_common_option(int opt, const char *optarg,
}
break;
}
+#endif /* !RTE_EXEC_ENV_WINDOWS */
case OPT_LCORES_NUM:
if (eal_parse_lcores(optarg) < 0) {
@@ -1735,6 +1739,7 @@ eal_common_usage(void)
" --"OPT_LOG_LEVEL"=<int> Set global log level\n"
" --"OPT_LOG_LEVEL"=<type-match>:<int>\n"
" Set specific log level\n"
+#ifndef RTE_EXEC_ENV_WINDOWS
" --"OPT_TRACE"=<regex-match>\n"
" Enable trace based on regular expression trace name.\n"
" By default, the trace is disabled.\n"
@@ -1758,6 +1763,7 @@ eal_common_usage(void)
" reaches its maximum limit.\n"
" Default mode is 'overwrite' and parameter\n"
" must be specified once only.\n"
+#endif /* !RTE_EXEC_ENV_WINDOWS */
" -v Display version information on startup\n"
" -h, --help This help\n"
" --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
diff --git a/lib/librte_eal/common/eal_common_thread.c b/lib/librte_eal/common/eal_common_thread.c
index 20dbcc7a0..f9f588c17 100644
--- a/lib/librte_eal/common/eal_common_thread.c
+++ b/lib/librte_eal/common/eal_common_thread.c
@@ -15,7 +15,9 @@
#include <rte_lcore.h>
#include <rte_memory.h>
#include <rte_log.h>
+#ifndef RTE_EXEC_ENV_WINDOWS
#include <rte_trace_point.h>
+#endif
#include "eal_internal_cfg.h"
#include "eal_private.h"
@@ -166,7 +168,10 @@ static void *rte_thread_init(void *arg)
pthread_barrier_destroy(¶ms->configured);
free(params);
}
+
+#ifndef RTE_EXEC_ENV_WINDOWS
__rte_trace_mem_per_thread_alloc();
+#endif
return start_routine(routine_arg);
}
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation
2020-04-26 15:38 ` Thomas Monjalon
@ 2020-04-26 16:42 ` Dmitry Kozlyuk
0 siblings, 0 replies; 19+ messages in thread
From: Dmitry Kozlyuk @ 2020-04-26 16:42 UTC (permalink / raw)
To: Thomas Monjalon
Cc: dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Jerin Jacob, Sunil Kumar Kori, Harini Ramakrishnan, Omar Cardona,
David Marchand
On 2020-04-26 17:38 GMT+0200 Thomas Monjalon wrote:
> I think this patch is doing too many things at once.
> Why not just disabling tracing on Windows for now,
> and apply proper patches for memory management, timer, endianness, etc
> in 20.08?
Sounds reasonable since tracing cannot be fully supported anyway and we're
past deadline. Replacing the series with a trivial patch for now.
> Some cosmetic comments below,
Thanks.
--
Dmitry Kozlyuk
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH v3] eal: disable tracing on Windows
2020-04-26 16:41 ` [dpdk-dev] [PATCH v3] eal: disable tracing on Windows Dmitry Kozlyuk
@ 2020-04-26 17:46 ` Jerin Jacob
2020-04-26 18:10 ` Thomas Monjalon
0 siblings, 1 reply; 19+ messages in thread
From: Jerin Jacob @ 2020-04-26 17:46 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Thomas Monjalon, Sunil Kumar Kori, David Marchand, Jerin Jacob
On Sun, Apr 26, 2020 at 10:12 PM Dmitry Kozlyuk
<dmitry.kozliuk@gmail.com> wrote:
>
> Fix build errors caused by using Unix-specific functions in common code.
> Hide and disable command-line options related to tracing on Windows.
>
> Fixes: 3d26a70ae338 ("trace: add trace configuration parameter")
> Fixes: 3b155d24bdaf ("trace: hook subsystem to Linux")
>
> Reported-by: Pallavi Kadam <pallavi.kadam@intel.com>
> Suggested-by: Thomas Monjalon <thomas@monjalon.net>
> Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
> ---
> lib/librte_eal/common/eal_common_options.c | 6 ++++++
> lib/librte_eal/common/eal_common_thread.c | 5 +++++
> 2 files changed, 11 insertions(+)
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH v3] eal: disable tracing on Windows
2020-04-26 17:46 ` Jerin Jacob
@ 2020-04-26 18:10 ` Thomas Monjalon
0 siblings, 0 replies; 19+ messages in thread
From: Thomas Monjalon @ 2020-04-26 18:10 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: Jerin Jacob, dpdk-dev, Pallavi Kadam, Narcisa Ana Maria Vasile,
Ranjit Menon, Sunil Kumar Kori, David Marchand, Jerin Jacob
26/04/2020 19:46, Jerin Jacob:
> On Sun, Apr 26, 2020 at 10:12 PM Dmitry Kozlyuk
> <dmitry.kozliuk@gmail.com> wrote:
> >
> > Fix build errors caused by using Unix-specific functions in common code.
> > Hide and disable command-line options related to tracing on Windows.
> >
> > Fixes: 3d26a70ae338 ("trace: add trace configuration parameter")
> > Fixes: 3b155d24bdaf ("trace: hook subsystem to Linux")
> >
> > Reported-by: Pallavi Kadam <pallavi.kadam@intel.com>
> > Suggested-by: Thomas Monjalon <thomas@monjalon.net>
> > Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
>
> Acked-by: Jerin Jacob <jerinj@marvell.com>
Applied, thanks
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API Dmitry Kozlyuk
@ 2020-05-04 20:14 ` Narcisa Ana Maria Vasile
0 siblings, 0 replies; 19+ messages in thread
From: Narcisa Ana Maria Vasile @ 2020-05-04 20:14 UTC (permalink / raw)
To: Dmitry Kozlyuk
Cc: dev, Pallavi Kadam, Narcisa Ana Maria Vasile, Ranjit Menon,
Jerin Jacob, Sunil Kumar Kori, Bruce Richardson
On Sun, Apr 26, 2020 at 06:28:17PM +0300, Dmitry Kozlyuk wrote:
> 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 <dmitry.kozliuk@gmail.com>
> ---
Acked-by: Narcisa Vasile <navasile@linux.microsoft.com>
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2020-05-04 20:14 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-26 3:22 [dpdk-dev] [PATCH 0/2] eal/windows: fix build by supporing trace Dmitry Kozlyuk
2020-04-26 3:22 ` [dpdk-dev] [PATCH 1/2] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
2020-04-26 11:14 ` Jerin Jacob
2020-04-26 3:22 ` [dpdk-dev] [PATCH 2/2] eal/windows: fix build by supporting trace Dmitry Kozlyuk
2020-04-26 11:32 ` Jerin Jacob
2020-04-26 12:02 ` Dmitry Kozlyuk
2020-04-26 12:23 ` Jerin Jacob
2020-04-26 12:36 ` Thomas Monjalon
2020-04-26 12:50 ` Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 0/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 1/3] eal/windows: replace sys/queue.h with a complete one from FreeBSD Dmitry Kozlyuk
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 2/3] eal: add internal directory management API Dmitry Kozlyuk
2020-05-04 20:14 ` Narcisa Ana Maria Vasile
2020-04-26 15:28 ` [dpdk-dev] [PATCH v2 3/3] eal/windows: fix build by enabling trace compilation Dmitry Kozlyuk
2020-04-26 15:38 ` Thomas Monjalon
2020-04-26 16:42 ` Dmitry Kozlyuk
2020-04-26 16:41 ` [dpdk-dev] [PATCH v3] eal: disable tracing on Windows Dmitry Kozlyuk
2020-04-26 17:46 ` Jerin Jacob
2020-04-26 18:10 ` Thomas Monjalon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).