From 6ce060a01c92616141cfba240a76036c31bf1d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Thu, 17 Mar 2022 13:57:46 +0100 Subject: [PATCH] Squashed 'src/deps/miniasync/' changes from dd06ea790..3a5e92e49 3a5e92e49 Merge pull request #68 from lukaszstolarczuk/run-examples-only-if-built 0a06e589a test: run examples only if they are built f3519cb4e Merge pull request #62 from pbalcer/fix-chained-futures 99e22a353 masync: fix possible alignment issues in chained futures da12cb146 Merge pull request #61 from pbalcer/poll-on-complete d348226bd masync: make future safe to poll when complete 88d3f38f9 Merge pull request #57 from kswiecicki/masync-expand-docs 97f5fd863 masync: expand the documentation 385dd474b Merge pull request #60 from DamianDuy/enableWXFlag c325d2562 common: enable -WX flag on Windows 38e3ae7f5 Merge pull request #50 from pbalcer/simpler-membuf 5afd6f5f8 masync: simplify membuf memory reclamation 7b6bc3dcc Merge pull request #59 from wlemkows/KW-fixes 4404106c2 common: rm some dead code 97644e053 Merge pull request #58 from wlemkows/KW-fixes 12f8fa017 common: fix Cov issue edddf7616 Merge pull request #53 from blazej-smorawski/vdm-add-memcpy-fn ab6de8304 Merge pull request #56 from wlemkows/KW-fixes 2ede89338 common: fix KW issues and other fixes 1ae12b89d masync: vdm threads add data function pointers array 3c52ffe0c Merge pull request #55 from DamianDuy/fixNonStandardExtensionWinWarnings 4d6dff9b5 common: suppress conditional expression is const warning 7eac0dba2 common: fix nameless union/struct warning git-subtree-dir: src/deps/miniasync git-subtree-split: 3a5e92e49bb31e168c9a9b2446c9b1875347a03b --- CMakeLists.txt | 3 +- doc/CMakeLists.txt | 59 ++--- doc/data_mover_dml_get_vdm.3.md | 56 +++++ doc/data_mover_dml_new.3.md | 56 +++++ doc/data_mover_sync_get_vdm.3.md | 56 +++++ doc/data_mover_sync_new.3.md | 56 +++++ doc/data_mover_threads_get_vdm.3.md | 56 +++++ doc/data_mover_threads_new.3.md | 83 +++++++ doc/future_context_get_data.3.md | 51 +++++ doc/future_context_get_output.3.md | 51 +++++ doc/future_context_get_size.3.md | 50 +++++ doc/future_poll.3.md | 65 ++++++ doc/manuals.txt | 20 ++ doc/miniasync.7.md | 59 +++++ doc/miniasync.7.md.in | 32 --- doc/miniasync_future.3.md.in | 69 ------ doc/miniasync_future.7.md | 182 ++++++++++++++++ doc/miniasync_runtime.3.md.in | 73 ------- doc/miniasync_runtime.7.md | 56 +++++ doc/miniasync_vdm.3.md.in | 71 ------ doc/miniasync_vdm.7.md | 82 +++++++ doc/miniasync_vdm_dml.3.md.in | 84 ------- doc/miniasync_vdm_dml.7.md | 86 ++++++++ doc/miniasync_vdm_synchronous.3.md.in | 64 ------ doc/miniasync_vdm_synchronous.7.md | 68 ++++++ doc/miniasync_vdm_threads.3.md.in | 82 ------- doc/miniasync_vdm_threads.7.md | 81 +++++++ doc/runtime_new.3.md | 55 +++++ doc/runtime_wait.3.md | 69 ++++++ doc/vdm_memcpy.3.md | 85 ++++++++ examples/basic-async/basic-async.c | 65 ++++-- examples/basic/basic.c | 5 +- extras/dml/CMakeLists.txt | 22 +- extras/dml/README.md | 18 +- extras/dml/data_mover_dml.c | 44 +--- ...miniasync-dml.h => libminiasync-vdm-dml.h} | 11 +- .../data_mover_dml.h | 0 extras/dml/utils/util_dml.h | 2 +- src/core/membuf.c | 108 ++++++--- src/core/membuf.h | 31 +-- src/core/os.h | 17 -- src/core/os_posix.c | 68 ------ src/core/os_windows.c | 140 +----------- src/core/ringbuf.c | 51 +++-- src/core/util.h | 1 - src/core/util_posix.c | 33 +-- src/core/util_windows.c | 9 - src/data_mover_sync.c | 37 ++-- src/data_mover_threads.c | 80 +++---- src/include/libminiasync/data_mover_threads.h | 8 +- src/include/libminiasync/future.h | 24 +- src/include/libminiasync/vdm.h | 12 +- src/windows/include/platform.h | 1 - tests/CMakeLists.txt | 23 +- tests/data_mover_dml/data_mover_dml.c | 2 +- tests/future/test_future.c | 205 ++++++++++++++++++ tests/future/test_future.cmake | 19 ++ tests/membuf/membuf_simple.c | 68 ++---- tests/test_helpers.h | 5 + utils/docker/images/Dockerfile.fedora-35 | 2 +- utils/docker/images/Dockerfile.ubuntu-21.04 | 2 +- 61 files changed, 2001 insertions(+), 1072 deletions(-) create mode 100644 doc/data_mover_dml_get_vdm.3.md create mode 100644 doc/data_mover_dml_new.3.md create mode 100644 doc/data_mover_sync_get_vdm.3.md create mode 100644 doc/data_mover_sync_new.3.md create mode 100644 doc/data_mover_threads_get_vdm.3.md create mode 100644 doc/data_mover_threads_new.3.md create mode 100644 doc/future_context_get_data.3.md create mode 100644 doc/future_context_get_output.3.md create mode 100644 doc/future_context_get_size.3.md create mode 100644 doc/future_poll.3.md create mode 100644 doc/manuals.txt create mode 100644 doc/miniasync.7.md delete mode 100644 doc/miniasync.7.md.in delete mode 100644 doc/miniasync_future.3.md.in create mode 100644 doc/miniasync_future.7.md delete mode 100644 doc/miniasync_runtime.3.md.in create mode 100644 doc/miniasync_runtime.7.md delete mode 100644 doc/miniasync_vdm.3.md.in create mode 100644 doc/miniasync_vdm.7.md delete mode 100644 doc/miniasync_vdm_dml.3.md.in create mode 100644 doc/miniasync_vdm_dml.7.md delete mode 100644 doc/miniasync_vdm_synchronous.3.md.in create mode 100644 doc/miniasync_vdm_synchronous.7.md delete mode 100644 doc/miniasync_vdm_threads.3.md.in create mode 100644 doc/miniasync_vdm_threads.7.md create mode 100644 doc/runtime_new.3.md create mode 100644 doc/runtime_wait.3.md create mode 100644 doc/vdm_memcpy.3.md rename extras/dml/include/{libminiasync-dml.h => libminiasync-vdm-dml.h} (62%) rename extras/dml/include/{libminiasync-dml => libminiasync-vdm-dml}/data_mover_dml.h (100%) create mode 100644 tests/future/test_future.c create mode 100644 tests/future/test_future.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c38d702aa0c..ef221cdbe9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,7 @@ if(WIN32) # It looks like the issue is still unfixed: # https://developercommunity.visualstudio.com/t/several-warnings-in-windows-sdk-100177630-in-windo/435362 add_flag(-DWIN32_LEAN_AND_MEAN) -# Enable when all Warnings are fixed. - #add_flag(-WX) + add_compile_options(/W3 /WX) endif() if(USE_ASAN) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 8fd5e046681..f2bdec497af 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -42,53 +42,30 @@ find_program(PANDOC NAMES pandoc) if(PANDOC) message(STATUS "Found pandoc: ${PANDOC}") - ## Manpages without any examples - # miniasync.7 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync.7.md.in - ${MAN_DIR}/tmp/miniasync.7.md) - configure_man(miniasync.7 ${MAN_DIR}/tmp/miniasync.7.md) + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/manuals.txt man_list) - # miniasync_future.3 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync_future.3.md.in - ${MAN_DIR}/tmp/miniasync_future.3.md) - configure_man(miniasync_future.3 ${MAN_DIR}/tmp/miniasync_future.3.md) - add_manpage_links(miniasync_future.3 - future_context_get_data future_context_get_output future_context_get_size - FUTURE FUTURE_INIT FUTURE_AS_RUNNABLE FUTURE_OUTPUT FUTURE_CHAIN_ENTRY - FUTURE_CHAIN_ENTRY_INIT FUTURE_BUSY_POLL FUTURE_CHAIN_INIT) + foreach(man ${man_list}) + configure_man(${man} ${CMAKE_CURRENT_SOURCE_DIR}/${man}.md) + endforeach(man man_list) + + add_manpage_links(data_mover_dml_new.3 + data_mover_dml_delete) - # miniasync_runtime.3 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync_runtime.3.md.in - ${MAN_DIR}/tmp/miniasync_runtime.3.md) - configure_man(miniasync_runtime.3 ${MAN_DIR}/tmp/miniasync_runtime.3.md) - add_manpage_links(miniasync_runtime.3 - runtime_new runtime_delete runtime_wait_multiple runtime_wait) + add_manpage_links(data_mover_sync_new.3 + data_mover_sync_delete) - # miniasync_vdm.3 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync_vdm.3.md.in - ${MAN_DIR}/tmp/miniasync_vdm.3.md) - configure_man(miniasync_vdm.3 ${MAN_DIR}/tmp/miniasync_vdm.3.md) - add_manpage_links(miniasync_vdm.3 vdm_memcpy vdm_new vdm_delete) + add_manpage_links(data_mover_threads_new.3 + data_mover_threads_delete) - # miniasync_vdm_synchronous.3 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync_vdm_synchronous.3.md.in - ${MAN_DIR}/tmp/miniasync_vdm_synchronous.3.md) - configure_man(miniasync_vdm_synchronous.3 ${MAN_DIR}/tmp/miniasync_vdm_synchronous.3.md) - add_manpage_links(miniasync_vdm_synchronous.3 vdm_descriptor_synchronous) + add_manpage_links(miniasync_future.7 + FUTURE FUTURE_INIT FUTURE_AS_RUNNABLE FUTURE_OUTPUT FUTURE_CHAIN_ENTRY + FUTURE_CHAIN_ENTRY_INIT FUTURE_BUSY_POLL FUTURE_CHAIN_INIT) - # miniasync_vdm_threads.3 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync_vdm_threads.3.md.in - ${MAN_DIR}/tmp/miniasync_vdm_threads.3.md) - configure_man(miniasync_vdm_threads.3 ${MAN_DIR}/tmp/miniasync_vdm_threads.3.md) - add_manpage_links(miniasync_vdm_threads.3 - vdm_descriptor_threads vdm_descriptor_threads_polled) + add_manpage_links(runtime_new.3 + runtime_delete) - # miniasync_vdm_dml.3 - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/miniasync_vdm_dml.3.md.in - ${MAN_DIR}/tmp/miniasync_vdm_dml.3.md) - configure_man(miniasync_vdm_dml.3 ${MAN_DIR}/tmp/miniasync_vdm_dml.3.md) - add_manpage_links(miniasync_vdm_dml.3 - vdm_descriptor_dml vdm_descriptor_dml_async) + add_manpage_links(runtime_wait.3 + runtime_wait_multiple) # install manpages install(FILES ${MAN_DIR}/miniasync.7 diff --git a/doc/data_mover_dml_get_vdm.3.md b/doc/data_mover_dml_get_vdm.3.md new file mode 100644 index 00000000000..b724a29cac7 --- /dev/null +++ b/doc/data_mover_dml_get_vdm.3.md @@ -0,0 +1,56 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(DATA_MOVER_DML_GET_VDM, 3) +collection: miniasync +header: DATA_MOVER_DML_GET_VDM +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (data_mover_dml_get_vdm.3 -- man page for miniasync data_mover_dml_get_vdm operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**data_mover_dml_get_vdm**() - get virtual data mover structure from the **DML** +data mover structure + +# SYNOPSIS # + +```c +#include + +struct vdm; +struct data_mover_dml; + +struct vdm *data_mover_dml_get_vdm(struct data_mover_dml *dmd); +``` + +For general description of **DML** data mover API, see **miniasync_vdm_dml**(7). + +# DESCRIPTION # + +The **data_mover_dml_get_vdm**() function reads the virtual data mover structure +from the **DML** data mover structure pointed by *dmd*. Virtual data mover +structure *struct vdm* is needed by every **miniasync**(7) data mover operation. + +**DML** data mover implementation supports following operations: + +* **vdm_memcpy**(3) - memory copy operation + +# RETURN VALUE # + +The **data_mover_dml_get_vdm**() function returns a pointer to *struct vdm* structure. + +# SEE ALSO # + +**vdm_memcpy**(3), **miniasync**(7), +**miniasync_vdm_dml**(7) and **** diff --git a/doc/data_mover_dml_new.3.md b/doc/data_mover_dml_new.3.md new file mode 100644 index 00000000000..c1e51fcbabc --- /dev/null +++ b/doc/data_mover_dml_new.3.md @@ -0,0 +1,56 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(DATA_MOVER_DML_NEW, 3) +collection: miniasync +header: DATA_MOVER_DML_NEW +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (data_mover_dml_new.3 -- man page for miniasync data_mover_dml_new operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**data_mover_dml_new**(), **data_mover_dml_delete**() - allocate or free **DML** +data mover structure + +# SYNOPSIS # + +```c +#include + +struct data_mover_dml; + +struct data_mover_dml *data_mover_dml_new(void); +void data_mover_dml_delete(struct data_mover_dml *dmd); +``` + +For general description of **DML** data mover API, see **miniasync_vdm_dml**(7). + +# DESCRIPTION # + +The **data_mover_dml_new**() function allocates and initializes a new **DML** data mover structure. + +The **data_mover_dml_delete**() function frees and finalizes the **DML** data mover structure +pointed by *dmd*. + +# RETURN VALUE # + +The **data_mover_dml_new**() function returns a pointer to *struct data_mover_dml* structure or +**NULL** if the allocation or initialization failed. + +The **data_mover_dml_delete**() function does not return any value. + +# SEE ALSO # + +**miniasync**(7), **miniasync_vdm_dml**(7), +**** and **** diff --git a/doc/data_mover_sync_get_vdm.3.md b/doc/data_mover_sync_get_vdm.3.md new file mode 100644 index 00000000000..593f4c65cf6 --- /dev/null +++ b/doc/data_mover_sync_get_vdm.3.md @@ -0,0 +1,56 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(DATA_MOVER_SYNC_GET_VDM, 3) +collection: miniasync +header: DATA_MOVER_SYNC_GET_VDM +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (data_mover_sync_get_vdm.3 -- man page for miniasync data_mover_sync_get_vdm operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**data_mover_sync_get_vdm**() - get virtual data mover structure from the synchronous +data mover structure + +# SYNOPSIS # + +```c +#include + +struct vdm; +struct data_mover_sync; + +struct vdm *data_mover_sync_get_vdm(struct data_mover_sync *dms); +``` + +For general description of synchronous data mover API, see **miniasync_vdm_synchronous**(7). + +# DESCRIPTION # + +The **data_mover_sync_get_vdm**() function reads the virtual data mover structure +from the synchronous data mover structure pointed by *dms*. Virtual data mover +structure *struct vdm* is needed by every **miniasync**(7) data mover operation. + +Synchronous data mover implementation supports following operations: + +* **vdm_memcpy**(3) - memory copy operation + +# RETURN VALUE # + +The **data_mover_sync_get_vdm**() function returns a pointer to *struct vdm* structure. + +# SEE ALSO # + +**vdm_memcpy**(3), **miniasync**(7), +**miniasync_vdm_synchronous**(7) and **** diff --git a/doc/data_mover_sync_new.3.md b/doc/data_mover_sync_new.3.md new file mode 100644 index 00000000000..c83de0477d2 --- /dev/null +++ b/doc/data_mover_sync_new.3.md @@ -0,0 +1,56 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(DATA_MOVER_SYNC_NEW, 3) +collection: miniasync +header: DATA_MOVER_SYNC_NEW +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (data_mover_sync_new.3 -- man page for miniasync data_mover_sync_new operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**data_mover_sync_new**(), **data_mover_sync_delete**() - allocate or free synchronous +data mover structure + +# SYNOPSIS # + +```c +#include + +struct data_mover_sync; + +struct data_mover_sync *data_mover_sync_new(void); +void data_mover_sync_delete(struct data_mover_sync *dms); +``` + +For general description of synchronous data mover API, see **miniasync_vdm_synchronous**(7). + +# DESCRIPTION # + +The **data_mover_sync_new**() function allocates and initializes a new synchronous data mover structure. + +The **data_mover_sync_delete**() function frees and finalizes the synchronous data mover structure +pointed by *dms*. + +# RETURN VALUE # + +The **data_mover_sync_new**() function returns a pointer to *struct data_mover_sync* structure or +**NULL** if the allocation or initialization failed. + +The **data_mover_sync_delete**() function does not return any value. + +# SEE ALSO # + +**miniasync**(7), **miniasync_vdm_synchronous**(7) +and **** diff --git a/doc/data_mover_threads_get_vdm.3.md b/doc/data_mover_threads_get_vdm.3.md new file mode 100644 index 00000000000..0ed21762b69 --- /dev/null +++ b/doc/data_mover_threads_get_vdm.3.md @@ -0,0 +1,56 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(DATA_MOVER_THREADS_GET_VDM, 3) +collection: miniasync +header: DATA_MOVER_THREADS_GET_VDM +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (data_mover_threads_get_vdm.3 -- man page for miniasync data_mover_threads_get_vdm operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**data_mover_threads_get_vdm**() - get virtual data mover structure from the thread +data mover structure + +# SYNOPSIS # + +```c +#include + +struct vdm; +struct data_mover_threads; + +struct vdm *data_mover_threads_get_vdm(struct data_mover_threads *dmt); +``` + +For general description of thread data mover API, see **miniasync_vdm_threads**(7). + +# DESCRIPTION # + +The **data_mover_threads_get_vdm**() function reads the virtual data mover structure +from the thread data mover structure pointed by *dms*. Virtual data mover structure +*struct vdm* is needed by every **miniasync**(7) data mover operation. + +Thread data mover implementation supports following operations: + +* **vdm_memcpy**(3) - memory copy operation + +# RETURN VALUE # + +The **data_mover_threads_get_vdm**() function returns a pointer to *struct vdm* structure. + +# SEE ALSO # + +**vdm_memcpy**(3), **miniasync**(7), +**miniasync_vdm_threads**(7) and **** diff --git a/doc/data_mover_threads_new.3.md b/doc/data_mover_threads_new.3.md new file mode 100644 index 00000000000..a75adfab1ed --- /dev/null +++ b/doc/data_mover_threads_new.3.md @@ -0,0 +1,83 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(DATA_MOVER_THREADS_NEW, 3) +collection: miniasync +header: DATA_MOVER_THREADS_NEW +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (data_mover_threads_new.3 -- man page for miniasync data_mover_threads_new operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**data_mover_threads_new**(), **data_mover_threads_delete**(), +**data_mover_threads_default**() - allocate, free or allocate with default parameters +threads data mover structure + +# SYNOPSIS # + +```c +#include + +enum future_notifier_type { + FUTURE_NOTIFIER_NONE, + FUTURE_NOTIFIER_WAKER, + FUTURE_NOTIFIER_POLLER, +}; + +struct data_mover_threads; + +struct data_mover_threads *data_mover_threads_new(size_t nthreads, + size_t ringbuf_size, enum future_notifier_type desired_notifier); +void data_mover_threads_delete(struct data_mover_threads *dmt); +struct data_mover_threads *data_mover_threads_default(); +``` + +For general description of thread data mover API, see **miniasync_vdm_threads**(7). + +# DESCRIPTION # + +The **data_mover_threads_new**() function allocates and initializes a new thread +data mover structure. This function spawns *nthreads* working threads during +initialization. Each thread data mover instance creates an internal ringuffer with +size *ringbuf_size* bytes, it is needed for allocations associated with data mover +operations. *desired_notifier* parameter specifies the notifier type that should +be used. + +The **data_mover_threads_default**() function allocates and initialzied a new thread +data mover structure with default parameters. It spanws *12* threads and creates a +ringbuffer with size of *128* bytes. + +Currently, thread data mover supports following notifer types: + +* **FUTURE_NOTIFIER_NONE** + +* **FUTURE_NOTIFIER_WAKER** + +For more information about notifiers, see **miniasync_future**(7). + +The **data_mover_threads_delete**() function frees and finalizes the synchronous +data mover structure pointed by *dms*. Spawned threads are cleaned up during +finalization. + +# RETURN VALUE # + +**data_mover_threads_new**() and data_mover_threads_default functions return a pointer +to *struct data_mover_sync* structure or **NULL** if the allocation or initialization failed. + +The **data_mover_threads_delete**() function does not return any value. + +# SEE ALSO # + +**miniasync**(7), **miniasync_future**(7), +**miniasync_vdm_threads**(7) and **** diff --git a/doc/future_context_get_data.3.md b/doc/future_context_get_data.3.md new file mode 100644 index 00000000000..89b62d32d0a --- /dev/null +++ b/doc/future_context_get_data.3.md @@ -0,0 +1,51 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(FUTURE_CONTEXT_GET_DATA, 3) +collection: miniasync +header: FUTURE_CONTEXT_GET_DATA +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (future_context_get_data.3 -- man page for miniasync future_context_get_data operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**future_context_get_data**() - get future data from future context + +# SYNOPSIS # + +```c +#include + +struct future_context; +void *future_context_get_data(struct future_context *context); +``` + +For general description of future API, see **miniasync_future**(7). + +# DESCRIPTION # + +The **future_context_get_data**() function reads the data from future context *context*. +Data type corresponds to the *\_data_type* parameter that is provided to the +**FUTURE(_name, _data_type, _output_type)** macro during future creation. + +For more information about the usage of **future_context_get_data**() function, see *basic* +example in *example* directory in miniasync repository . + +## RETURN VALUE ## + +The **future_context_get_data**() function returns pointer to the future data. + +# SEE ALSO # + +**miniasync**(7), **miniasync_future**(7) and **** diff --git a/doc/future_context_get_output.3.md b/doc/future_context_get_output.3.md new file mode 100644 index 00000000000..a467c2e9c70 --- /dev/null +++ b/doc/future_context_get_output.3.md @@ -0,0 +1,51 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(FUTURE_CONTEXT_GET_OUTPUT, 3) +collection: miniasync +header: FUTURE_CONTEXT_GET_OUTPUT +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (future_context_get_output.3 -- man page for miniasync future_context_get_output operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**future_context_get_output**() - get future output from future context + +# SYNOPSIS # + +```c +#include + +struct future_context; +void *future_context_get_output(struct future_context *context); +``` + +For general description of future API, see **miniasync_future**(7). + +# DESCRIPTION # + +The **future_context_get_output**() function reads the output from future context *context*. +Output type corresponds to the *\_output_type* parameter that is provided to the +**FUTURE(_name, _data_type, _output_type)** macro during future creation. + +For more information about the usage of **future_context_get_output**() function, see *basic* +example in *example* directory in miniasync repository . + +## RETURN VALUE ## + +The **future_context_get_output**() function returns pointer to the future output. + +# SEE ALSO # + +**miniasync**(7), **miniasync_future**(7) and **** diff --git a/doc/future_context_get_size.3.md b/doc/future_context_get_size.3.md new file mode 100644 index 00000000000..b79a0862018 --- /dev/null +++ b/doc/future_context_get_size.3.md @@ -0,0 +1,50 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(FUTURE_CONTEXT_GET_SIZE, 3) +collection: miniasync +header: FUTURE_CONTEXT_GET_SIZE +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (future_context_get_size.3 -- man page for miniasync future_context_get_size operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**future_context_get_size**() - get the combined size of future data and output + +# SYNOPSIS # + +```c +#include + +struct future_context; +size_t future_context_get_size(struct future_context *context); +``` + +For general description of future API, see **miniasync_future**(7). + +# DESCRIPTION # + +The **future_context_get_size**() function reads the combined size of the data and output +structures from the future context *context*. Data structure type and output structure type +correspond respectively to the *\_data_type* and *\_output_type* parameters that are provided +to the **FUTURE(_name, _data_type, _output_type)** macro during future creation. + +## RETURN VALUE ## + +The **future_context_get_size**() function returns combined size of the future data and output +structures. + +# SEE ALSO # + +**miniasync**(7), **miniasync_future**(7) and **** diff --git a/doc/future_poll.3.md b/doc/future_poll.3.md new file mode 100644 index 00000000000..d8b54c866f1 --- /dev/null +++ b/doc/future_poll.3.md @@ -0,0 +1,65 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(FUTURE_POLL, 3) +collection: miniasync +header: FUTURE_POLL +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (future_poll.3 -- man page for miniasync future_poll operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**future_poll**() - poll the future + +# SYNOPSIS # + +```c +#include + +enum future_state; +struct future; +struct future_notifier; + +enum future_state future_poll(struct future *fut, + struct future_notifier *notifier); +``` + +For general description of future API, see **miniasync_future**(7). + +# DESCRIPTION # + +The **future_poll**() function makes implementation-defined operation towards +completion of the task associated with the future pointed by *fut*. + +Additionally, the **future_poll**() function can accept future notifier. +Future notifier *notifier* is an optional parameter that is passed to the future +task function. Future notifiers can be used to notify the caller that some progress +can be made and the future should be polled again. This can be used to avoid busy +polling. + +## RETURN VALUE ## + +The **future_poll**() function returns current state of the future. + +Future can be in one of the following states: + +* **FUTURE_STATE_IDLE** - future task has yet to begin execution + +* **FUTURE_STATE_RUNNING** - future task is in progress + +* **FUTURE_STATE_COMPLETE** - future task was completed + +# SEE ALSO # + +**miniasync**(7), **miniasync_future**(7) and **** diff --git a/doc/manuals.txt b/doc/manuals.txt new file mode 100644 index 00000000000..7c8ede8743c --- /dev/null +++ b/doc/manuals.txt @@ -0,0 +1,20 @@ +data_mover_dml_get_vdm.3 +data_mover_dml_new.3 +data_mover_sync_get_vdm.3 +data_mover_sync_new.3 +data_mover_threads_get_vdm.3 +data_mover_threads_new.3 +future_context_get_data.3 +future_context_get_output.3 +future_context_get_size.3 +future_poll.3 +miniasync.7 +miniasync_future.7 +miniasync_runtime.7 +miniasync_vdm.7 +miniasync_vdm_dml.7 +miniasync_vdm_synchronous.7 +miniasync_vdm_threads.7 +runtime_new.3 +runtime_wait.3 +vdm_memcpy.3 diff --git a/doc/miniasync.7.md b/doc/miniasync.7.md new file mode 100644 index 00000000000..b2f52bdf4db --- /dev/null +++ b/doc/miniasync.7.md @@ -0,0 +1,59 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC, 7) +collection: miniasync +header: MINIASYNC +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2021-2022, Intel Corporation) + +[comment]: <> (miniasync.7 -- man page for miniasync) + +[NAME](#name)
+[DESCRIPTION](#description)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync** - Mini Library for Asynchronous Programming in C + +# DESCRIPTION # + +**miniasync** is a minimalistic library used for asynchronous programming in C +programming language. It provides a **miniasync_future**(7) feature that is an +abstraction representing a task or a collection of tasks. Futures are meant to be +implemented by developers and used by applications to run multiple concurrent tasks. +Futures begin execution when they are polled for the first time, futures can be safely +polled until an **FUTURE_STATE_COMPLETE** state is returned, it means that the future +has finished its task. Polling completed future results in undefined behavior unless +the specific future implementation says otherwise. For more information about future API, +see **miniasync_future**(7). + +Futures can be polled in various ways, the simplest of them all is using **future_poll**(3) +function. **miniasync** library also provides the **miniasync_runtime**(7) feature that manages +the future polling behavior. Runtime makes use of optimized polling mechanisms that avoid busy +polling and simplifies the future polling process. Runtime is meant to be used together +with concrete future implementations. For more information about runtime API, see +**miniasync_runtime**(7). + +In case that the future is meant to execute an asynchronous memory operation, **miniasync** library +provides a **miniasync_vdm**(7) virtual data mover feature. Virtual data mover generalizes +asynchronous memory operations to avoid hard dependencies on any specific hardware offload +or memory operations. +**miniasync** provides the following virtual data mover implementations: + +* **miniasync_vdm_threads**(7) - an implementation based on system threads + +* **miniasync_vdm_dml**(7) - an implementation based on the *Data Mover Library* (**DML**) + +For more information about virtual data mover API, see **miniasync_vdm**(7). + +# SEE ALSO # + +**future_poll**(3), +**miniasync_future**(7), **miniasync_runtime**(7), +**miniasync_vdm**(7), **miniasync_vdm_dml**(7), +**miniasync_vdm_threads**(7) and **** diff --git a/doc/miniasync.7.md.in b/doc/miniasync.7.md.in deleted file mode 100644 index 93296d3d47f..00000000000 --- a/doc/miniasync.7.md.in +++ /dev/null @@ -1,32 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC, 7) -collection: miniasync -header: MINIASYNC -secondary_title: miniasync -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2021, Intel Corporation) - -[comment]: <> (miniasync.7 -- man page for miniasync) - -[NAME](#name)
-[DESCRIPTION](#description)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync** - Mini Library for Asynchronous Programming in C - - -# DESCRIPTION # - -XXX: add description here. - - -# SEE ALSO # - -**miniasync_future**(3), **miniasync_runtime**(3), **miniasync_vdm**(3) and **** diff --git a/doc/miniasync_future.3.md.in b/doc/miniasync_future.3.md.in deleted file mode 100644 index 8730294c1f6..00000000000 --- a/doc/miniasync_future.3.md.in +++ /dev/null @@ -1,69 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC_FUTURE, 3) -collection: miniasync -header: MINIASYNC_FUTURE -secondary_title: miniasync -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2021, Intel Corporation) - -[comment]: <> (miniasync_future.3 -- man page for miniasync future API) - -[NAME](#name)
-[SYNOPSIS](#synopsis)
-[DESCRIPTION](#description)
-[ERRORS](#errors)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync_future** - Future API for miniasync library - - -# SYNOPSIS # - -```c -#include - -void *future_context_get_data(struct future_context *context); -void *future_context_get_output(struct future_context *context); -size_t future_context_get_size(struct future_context *context); - -FUTURE(_name, _data_type, _output_type) -FUTURE_INIT(_futurep, _taskfn) -FUTURE_AS_RUNNABLE(futurep) (&(futurep)->base) -FUTURE_OUTPUT(futurep) -FUTURE_CHAIN_ENTRY(_future_type, _name) -FUTURE_CHAIN_ENTRY_INIT(_entry, _fut, _map, _map_arg) -FUTURE_BUSY_POLL(_futurep) -FUTURE_CHAIN_INIT(_futurep) -``` - -For general description of miniasync see **miniasync**(7). - - -# DESCRIPTION # - -XXX: add description here. - -`void *future_context_get_data(struct future_context *context);` - -: XXX add description here. - -`void *future_context_get_output(struct future_context *context);` - -: XXX add description here. - - -## ERRORS ## - -XXX add description here. - - -# SEE ALSO # - -**miniasync**(7), **miniasync_runtime**(3), **miniasync_vdm**(3) and **** diff --git a/doc/miniasync_future.7.md b/doc/miniasync_future.7.md new file mode 100644 index 00000000000..76f937c176e --- /dev/null +++ b/doc/miniasync_future.7.md @@ -0,0 +1,182 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC_FUTURE, 7) +collection: miniasync +header: MINIASYNC_FUTURE +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2021-2022, Intel Corporation) + +[comment]: <> (miniasync_future.7 -- man page for miniasync future API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[MACROS](#macros)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync_future** - Future API for miniasync library + +# SYNOPSIS # + +```c +#include + +typedef enum future_state (*future_task_fn)(struct future_context *context, + struct future_notifier *notifier); + +typedef void (*future_waker_wake_fn)(void *data); + +typedef void (*future_map_fn)(struct future_context *lhs, + struct future_context *rhs, void *arg); + +enum future_state { + FUTURE_STATE_IDLE, + FUTURE_STATE_COMPLETE, + FUTURE_STATE_RUNNING, +}; + +struct future_context { + size_t data_size; + size_t output_size; + enum future_state state; + uint32_t padding; +}; + +struct future_waker { + void *data; + future_waker_wake_fn wake; +}; + +struct future_poller { + uint64_t *ptr_to_monitor; +}; + +enum future_notifier_type { + FUTURE_NOTIFIER_NONE, + FUTURE_NOTIFIER_WAKER, + FUTURE_NOTIFIER_POLLER, +}; + +struct future_notifier { + struct future_waker waker; + struct future_poller poller; + enum future_notifier_type notifier_used; + uint32_t padding; +}; + +FUTURE(_name, _data_type, _output_type) +FUTURE_INIT(_futurep, _taskfn) +FUTURE_CHAIN_ENTRY(_future_type, _name) +FUTURE_CHAIN_ENTRY_INIT(_entry, _fut, _map, _map_arg) +FUTURE_CHAIN_INIT(_futurep) +FUTURE_AS_RUNNABLE(_futurep) +FUTURE_OUTPUT(_futurep) +FUTURE_BUSY_POLL(_futurep) +FUTURE_WAKER_WAKE(_wakerp) +``` + +For general description of future API, see **miniasync_future**(7). + +# DESCRIPTION # + +Future is an abstract type representing a task, or a collection of tasks, +that can be executed incrementally by polling until the operation +is complete. Futures are typically meant to be implemented by library +developers and then used by applications to concurrently run multiple, +possibly unrelated, tasks. + +A future contains the following context: +* current state of execution for the future +* a function pointer for the task +* structure for data which is the required state needed to perform the task +* structure for output to store the result of the task +* the size of the data and output structures (both can be 0) + +A future definition must begin with an instance of the *struct future* type, which +contains all common metadata for all futures, followed by the structures for +data and output. The library provides convenience macros to simplify +the definition of user-defined future types. See **MACROS** section for details. + +Applications must call the **future_poll**(3) method to make progress on the task +associated with the future. This function will perform an implementation-defined +operation towards completing the task and return the future's current state. +Futures are generally safe to poll until they are complete. Unless the documentation +for a specific future implementation indicates otherwise, futures can be moved in +memory and don't always have to be polled by the same thread. + +Optionally, future implementations can accept notifiers for use in polling. +Notifiers can be useful to avoid busy polling when the future is waiting for some +asynchronous operation to finish or for some resource to become available. +Currently, **miniasync**(7) supports only waker notifier type. + +A waker is a tuple composed of a function pointer and a data context pointer. +If a waker is supplied and consumed by a future, it will call the function with its +data pointer when the future can be polled again to make further progress. The caller +needs to make sure that the waker is safe to call until the future is complete or until +it supplies a different waker to the **future_poll**(3) method. The waker implementation +needs to be thread-safe. + +A future implementation supporting **FUTURE_NOTIFIER_WAKER** type of notifier can +use a **FUTURE_WAKER_WAKE(_wakerp)** macro to signal the caller that some progress +can be made and the future should be polled again. + +TODO: Mention **FUTURE_NOTIFIER_POLLER** when it becomes supported. + +For more information about the usage of future API, see *examples* directory +in miniasync repository . + +# MACROS # + +**FUTURE(_name, _data_type, _output_type)** macro defines a future structure with *\_name* +as its name. Besides internal data needed by the future API, the defined structure contains +data member of *\_data_type* type and output member of *\_output_type* type. User can +provide the data that may later be retrieved in the future task implementation using +**future_context_get_data**(3) function. Similarly, the output of the future task can be +retrieved using **future_context_get_output**(3) function. Combined size of data and output +structures can be retrieved using **future_context_get_size**(3) function. When the user has +no need for input or output data, *\_data_type* and *\_output_type* can be defined as empty structures. + +**FUTURE_INIT(_futurep, _taskfn)** macro assigns task function *\_taskfn* to the future pointed +by *\_futurep*. Task function must be of the *future_task_fn* type. + +**FUTURE_CHAIN_ENTRY(_future_type, _name)** macro defines the future chain entry of the *\_future_type* +type named *\_name*. Future chain entries are defined as the members of chained future data structure +using this macro. Chained future can be composed of multiple future chain entries that will be +executed sequentially in the order they were defined. + +**FUTURE_CHAIN_ENTRY_INIT(_entry, _fut, _map, _map_arg)** macro initializes the future chain +entry pointed by *\_entry*. It requires pointer to the future instance *\_fut*, address of the mapping +function *\_map* and the pointer to the argument for the mapping function *\_map_arg*. *\_fut* can either be +the instance of the future defined using **FUTURE(_name, _data_type, _output_type)** macro or a virtual +data mover future. *\_map* function must be of the *future_map_fn* type and is an optional parameter. +*map* function should define the mapping behavior of the data and output structures between chained +future entry *\_entry* that has finished and the chained future entry that is about to start its execution. +Chained future instance must initialize all of its future chain entries using this macro. + +**FUTURE_CHAIN_INIT(_futurep)** macro initializes the chained future at the address *\_futurep*. + +**FUTURE_AS_RUNNABLE(_futurep)** macro returns pointer to the runnable form of the future pointed by +*\_futurep*. Runnable form of the future is required as an argument in **runtime_wait**(3) and +**runtime_wait_multiple**(3) functions. + +**FUTURE_OUTPUT(_futurep)** macro returns the output of the future pointed by *\_futurep*. + +**FUTURE_BUSY_POLL(_futurep)** repeatedly polls the future pointed by *\_futurep* until +it completes its execution. This macro does not use optimized polling. + +**FUTURE_WAKER_WAKE(_wakerp)** macro performs implementation-defined wake operation. It takes +a pointer to the waker structure of *struct future_waker* type. + +# SEE ALSO # + +**future_context_get_data**(3), **future_context_get_output**(3), +**future_context_get_size**(3), **future_poll**(3), +**runtime_wait**(3), **runtime_wait_multiple**(3) +**miniasync**(7), **miniasync_runtime**(7), +**miniasync_vdm**(7) and **** diff --git a/doc/miniasync_runtime.3.md.in b/doc/miniasync_runtime.3.md.in deleted file mode 100644 index a426a62e9eb..00000000000 --- a/doc/miniasync_runtime.3.md.in +++ /dev/null @@ -1,73 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC_RUNTIME, 3) -collection: miniasync -header: MINIASYNC_FUTURE -secondary_title: miniasync -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2021, Intel Corporation) - -[comment]: <> (miniasync_runtime.3 -- man page for miniasync runtime API) - -[NAME](#name)
-[SYNOPSIS](#synopsis)
-[DESCRIPTION](#description)
-[ERRORS](#errors)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync_runtime** - Runtime API for miniasync library - - -# SYNOPSIS # - -```c -#include - -struct runtime; - -struct runtime *runtime_new(void); -void runtime_delete(struct runtime *runtime); -void runtime_wait_multiple(struct runtime *runtime, - struct future *futs[], size_t nfuts); -void runtime_wait(struct runtime *runtime, struct future *fut); -``` - -For general description of miniasync see **miniasync**(7). - - -# DESCRIPTION # - -XXX: add description here. - -`struct runtime *runtime_new(void);` - -: XXX add description here. - -`void runtime_delete(struct runtime *runtime);` - -: XXX add description here. - -`void runtime_wait_multiple(struct runtime *runtime, - struct future *futs[], size_t nfuts);` - -: XXX add description here. - -`void runtime_wait(struct runtime *runtime, struct future *fut);` - -: XXX add description here. - - -## ERRORS ## - -XXX add description here. - - -# SEE ALSO # - -**miniasync**(7), **miniasync_future**(3), **miniasync_vdm**(3) and **** diff --git a/doc/miniasync_runtime.7.md b/doc/miniasync_runtime.7.md new file mode 100644 index 00000000000..b63d11c6c2f --- /dev/null +++ b/doc/miniasync_runtime.7.md @@ -0,0 +1,56 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC_RUNTIME, 7) +collection: miniasync +header: MINIASYNC_RUNTIME +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2021-2022, Intel Corporation) + +[comment]: <> (miniasync_runtime.7 -- man page for miniasync runtime API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync_runtime** - Runtime API for miniasync library + +# SYNOPSIS # + +```c +#include +``` + +For general description of miniasync, see **miniasync**(7). + +# DESCRIPTION # + +Runtime is a future polling management feature. It should be used together +with concrete implementations of the future. + +**miniasync**(7) runtime provides methods for efficient polling of single or +multiple futures, **runtime_wait**(3) and **runtime_wait_multiple**(3) respectively. +It makes use of waker notifier feature to optimize future polling behavior. Thread calling +one of the wait functions polls each future until no further progress can be made, and then +goes to sleep for a period of time before repeating this process. Calling thread can be woken +ahead of schedule by the future whose implementation makes use of the waker +**FUTURE_WAKER_WAKE(_wakerp)** macro. This optimization allows the calling thread +to switch context and do some useful work instead of idle polling. +For more information about the waker feature, see **miniasync_future**(7). + +There's no support for multi-threaded task scheduling. + +For more information about the usage of runtime API, see *examples* directory +in miniasync repository . + +# SEE ALSO # + +**runtime_wait**(3), **runtime_wait_multiple**(3), +**miniasync**(7), **miniasync_future**(7), +**miniasync_vdm**(7) and **** diff --git a/doc/miniasync_vdm.3.md.in b/doc/miniasync_vdm.3.md.in deleted file mode 100644 index f6650ab69ea..00000000000 --- a/doc/miniasync_vdm.3.md.in +++ /dev/null @@ -1,71 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC_VDM, 3) -collection: miniasync -header: MINIASYNC_VDM -secondary_title: miniasync -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2022, Intel Corporation) - -[comment]: <> (miniasync_vdm.3 -- man page for miniasync vdm API) - -[NAME](#name)
-[SYNOPSIS](#synopsis)
-[DESCRIPTION](#description)
-[RETURN VALUE](#return-value)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync_vdm** - Virtual data mover API for miniasync library - - -# SYNOPSIS # - -```c -#include - -struct vdm *vdm_new(struct vdm_descriptor *descriptor); -void vdm_delete(struct vdm *vdm); -struct vdm_memcpy_future vdm_memcpy(struct vdm *vdm, void *dest, void *src, size_t n, uint64_t flags); -``` - -For general description of miniasync see **miniasync**(7). - - -# DESCRIPTION # - -API for miniasync library forming the basis of various virtual data movers. -```c -struct vdm *vdm_new(struct vdm_descriptor *descriptor); -``` -Creates a new instance of virtual data mover defined by the `descriptor` and performs -additional initialization if specified in the descriptor. For example, -creating instance of vdm with **vdm_descriptor_threads**(3) also calls a procedure that creates -necessary threads and data associated with them. -```c -void vdm_delete(struct vdm *vdm); -``` -Cleans up all memory allocated by **vdm_new** of the `vdm` instance and performs additional finalization -if specified in the descriptor of the vdm instance. -```c -struct vdm_memcpy_future vdm_memcpy(struct vdm *vdm, void *dest, void *src, size_t n, uint64_t flags); -``` -Initializes and returns a new memcpy future based on the virtual data mover instance `vdm`. -The parameters: `dest`, `src`, `n` are standard memcpy parameters. The `flags` -represents mover specific flags. For example, flags for dml mover that describe how -the memcpy will be performed by the mover. - -# RETURN VALUE # - -The **vdm_new** returns pointer to a `struct vdm` or **NULL** if the allocation of -`struct vdm` failed or the additional initialization failed. - -# SEE ALSO # - -**miniasync**(7), **miniasync_future**(3), **miniasync_runtime**(3), **miniasync_vdm_synchronous**(3), -**miniasync_vdm_threads**(3), **vdm_descriptor_threads**(3) and **** diff --git a/doc/miniasync_vdm.7.md b/doc/miniasync_vdm.7.md new file mode 100644 index 00000000000..b79de64e412 --- /dev/null +++ b/doc/miniasync_vdm.7.md @@ -0,0 +1,82 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC_VDM, 7) +collection: miniasync +header: MINIASYNC_VDM +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (miniasync_vdm.7 -- man page for miniasync vdm API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync_vdm** - virtual data mover API for miniasync library + +# SYNOPSIS # + +```c +#include + +typedef void *(*vdm_operation_new) + (struct vdm *vdm, const struct vdm_operation *operation); +typedef int (*vdm_operation_start)(void *op, struct future_notifier *n); +typedef enum future_state (*vdm_operation_check)(void *op); +typedef void (*vdm_operation_delete)(void *op, + struct vdm_operation_output *output); + +struct vdm { + vdm_operation_new op_new; + vdm_operation_delete op_delete; + vdm_operation_start op_start; + vdm_operation_check op_check; +}; + +enum vdm_operation_type { + VDM_OPERATION_MEMCPY, +}; +``` + +For general description of miniasync, see **miniasync**(7). + +# DESCRIPTION # + +Virtual data mover API forms the basis of various concrete data movers. +It is an abstraction that the data mover implementations should adapt for +compatibility with the **miniasync_future**(7) feature. + +*struct vdm* is a structure required by every virtual data mover operation, for +example **vdm_memcpy**(3). *struct vdm* has following members: + +* *op_new* - allocations and initializations needed by operation + +* *op_delete* - deallocations and finalizations of operation + +* *op_start* - data mover task that should be executed + +* *op_check* - data mover task status check + +Currently, virtual data mover API supports following operation types: + +* **VDM_OPERATION_MEMCPY** - a memory copy operation + +For more information about concrete data mover implementations, see **miniasync_vdm_threads**(7), +**miniasync_vdm_synchronous**(7) and **miniasync_vdm_dml**(7). + +For more information about the usage of virtual data mover API, see *examples* directory +in miniasync repository . + +# SEE ALSO # + +**vdm_memcpy**(3), +**miniasync**(7), **miniasync_future**(7), +**miniasync_vdm_dml**(7), **miniasync_vdm_synchronous**(7), +**miniasync_vdm_threads**(7) and **** diff --git a/doc/miniasync_vdm_dml.3.md.in b/doc/miniasync_vdm_dml.3.md.in deleted file mode 100644 index a2b9541aaf5..00000000000 --- a/doc/miniasync_vdm_dml.3.md.in +++ /dev/null @@ -1,84 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC_VDM_DML, 3) -collection: miniasync_dml -header: MINIASYNC_VDM_DML -secondary_title: miniasync_dml -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2022, Intel Corporation) - -[comment]: <> (miniasync_vdm_dml.3 -- man page for miniasync-dml vdm API) - -[NAME](#name)
-[SYNOPSIS](#synopsis)
-[DESCRIPTION](#description)
-[EXAMPLE](#example)
-[ERRORS](#errors)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync_vdm_dml** - Virtual data mover API for miniasync-dml library - - -# SYNOPSIS # - -```c -#include -#include - -struct vdm_descriptor *vdm_descriptor_dml(void); -``` - -For general description of miniasync see **miniasync**(7). - - -# DESCRIPTION # - -The **vdm_descriptor_dml**() is **miniasync**(7) virtual data mover -implementation of Data Mover Library (**DML**). - -`struct vdm_descriptor *vdm_descriptor_dml(void);` - -: Data Mover Library implementation of virtual data mover. It is a non-blocking copy operation. - By default, this operation executes using software path. Set *MINIASYNC_DML_F_PATH_HW* flag to - use hardware path. Hardware path enables use of hardware accelerators (e.g. Intel Data Streaming Accelerator) - for certain computations. - If you want to make use of hardware path, make sure that DML is installed with ```DML_HW``` option. - For more information about **DML**, see ****. - -XXX: add description how to use flags - -**libminiasync-dml** provides following flags: - -* **MINIASYNC_DML_F_MEM_DURABLE** - write to destination is identified as write to durable memory - -* **MINIASYNC_DML_F_PATH_HW** - operation executes using hardware path - -For more information about **miniasync-dml** compilation options, see *extras/dml/README.md* file -on miniasync repository . - - -# EXAMPLE # - -Example usage of **vdm_descriptor_dml**() function with **MINIASYNC_DML_F_MEM_DURABLE** flag: -```c -struct vdm *dml_mover = vdm_new(vdm_descriptor_dml()); -struct vdm_memcpy_future memcpy_fut = - vdm_memcpy(dml_mover, dest, src, copy_size, MINIASYNC_DML_F_MEM_DURABLE); -``` - - -## ERRORS ## - -**vdm_descriptor_dml**() function does not return any errors. - - -# SEE ALSO # - -**miniasync**(7), **miniasync_vdm**(3), **vdm_memcpy**(3), **vdm_new**(3), -**** and **** diff --git a/doc/miniasync_vdm_dml.7.md b/doc/miniasync_vdm_dml.7.md new file mode 100644 index 00000000000..8475d6d3518 --- /dev/null +++ b/doc/miniasync_vdm_dml.7.md @@ -0,0 +1,86 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC_VDM_DML, 7) +collection: miniasync_dml +header: MINIASYNC_VDM_DML +secondary_title: miniasync_dml +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (miniasync_vdm_dml.7 -- man page for miniasync-vdm-dml API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[EXAMPLE](#example)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync_vdm_dml** - **DML** implementation of **miniasync**(7) virtual data mover + +# SYNOPSIS # + +```c +#include +#include +``` + +For general description of virtual data mover API, see **miniasync**(7). + +# DESCRIPTION # + +**DML** data mover is an implementation of the virtual data mover based on +the *Data Mover Library*(**DML**). Every **DML** data mover operation +executes under the control of **DML**. + +**DML** data mover is separated from the primary **miniasync**(7) library. It's encapsulated +by the **miniasync-vdm-dml**(7) library that has dependency on the **DML** library. +For information about **miniasync_vdm_dml**() library compilation, see *extras/dml/README.md* file. + +**DML** data mover supports offloading certain computations to the hardware +accelerators (e.g. Intel® Data Streaming Accelerator) by using **MINIASYNC_DML_F_PATH_HW** +flag. To use this feature, make sure that **DML** library is installed with **DML_HW** option. +For more information about **DML**, see ****. +An example of **DML** data mover API usage with flags can be found in **EXAMPLE** section. + +When the future is polled for the first time the data mover operation will be executed +asynchronously under the control of **DML** library. **DML** data mover does not +block the calling thread + +To create a new **DML** data mover instance, use **data_mover_dml_new**(3) function. + +**DML** data mover provides the following flags: + +* **MINIASYNC_DML_F_MEM_DURABLE** - write to destination is identified as write to durable memory + +* **MINIASYNC_DML_F_PATH_HW** - use hardware accelerators (e.g. Intel® Data Streaming Accelerator) +for operation execution + +**DML** data mover supports following operations: + +* **vdm_memcpy**(3) - memory copy operation + +**DML** data mover does not support notifier feature. For more information about +notifiers, see **miniasync_future**(7). + +# EXAMPLE # + +Example usage of **DML** data mover **vdm_memcpy**(3) operation with +**MINIASYNC_DML_F_MEM_DURABLE** flag: +```c +struct data_mover_dml *dmd = data_mover_dml_new(); +struct vdm *dml_mover = data_mover_dml_get_vdm(dmd); +struct vdm_memcpy_future memcpy_fut = vdm_memcpy(dml_mover, dest, src, + copy_size, MINIASYNC_DML_F_MEM_DURABLE); +``` + +# SEE ALSO # + +**data_mover_dml_new**(3), **data_mover_dml_get_vdm**(3), +**vdm_memcpy**(3), **miniasync**(7), **miniasync_future**(7), +**miniasync_vdm**(7), **** +and **** diff --git a/doc/miniasync_vdm_synchronous.3.md.in b/doc/miniasync_vdm_synchronous.3.md.in deleted file mode 100644 index 3e920ca3c68..00000000000 --- a/doc/miniasync_vdm_synchronous.3.md.in +++ /dev/null @@ -1,64 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC_VDM_SYNCHRONOUS, 3) -collection: miniasync -header: MINIASYNC_VDM_SYNCHRONOUS -secondary_title: miniasync -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2022, Intel Corporation) - -[comment]: <> (miniasync_vdm_synchronous.3 -- man page for miniasync vdm API) - -[NAME](#name)
-[SYNOPSIS](#synopsis)
-[DESCRIPTION](#description)
-[RETURN VALUE](#return-value)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync_vdm_synchronous** - Synchronous virtual data mover for miniasync - - -# SYNOPSIS # - -```c -#include - -struct vdm_descriptor *vdm_descriptor_synchronous(void); -``` - -For general description of miniasync see **miniasync**(7). - - -# DESCRIPTION # - -In order to use synchronous memcpy performed on the main thread, use following -descriptor: -```c -struct vdm_descriptor *vdm_descriptor_synchronous(void); -``` -Then, create a new virtual data mover instance using this descriptor and a new -future: -```c -struct vdm *vdm = vdm_new(vdm_descriptor_synchronous); -struct vdm_memcpy_future fut = vdm_memcpy(vdm, dst, src, size, flags); -``` - -Now, when the future is polled for the first time in **runtime_wait**(3) -the memcpy operation will be performed synchronously on the same thread as -**runtime_wait**(3). - -# RETURN VALUE # - -The **vdm_descriptor_synchronous** returns a pointer to `struct vdm_descriptor` -describing synchronous virtual data mover. - -# SEE ALSO # - -**miniasync**(7), **miniasync_future**(3), **miniasync_runtime**(3),**miniasync_vdm**(3), -**runtime_wait**(3), **vdm_memcpy**(3), **vdm_new**(3) and **** diff --git a/doc/miniasync_vdm_synchronous.7.md b/doc/miniasync_vdm_synchronous.7.md new file mode 100644 index 00000000000..8f8a08698be --- /dev/null +++ b/doc/miniasync_vdm_synchronous.7.md @@ -0,0 +1,68 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC_VDM_SYNCHRONOUS, 7) +collection: miniasync +header: MINIASYNC_VDM_SYNCHRONOUS +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (miniasync_vdm_synchronous.7 -- man page for miniasync vdm synchronous mover API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[EXAMPLE](#example)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync_vdm_synchronous** - synchronous implementation of **miniasync**(7) +virtual data mover + +# SYNOPSIS # + +```c +#include +``` + +For general description of virtual data mover API, see **miniasync**(7). + +# DESCRIPTION # + +Synchronous data mover is a synchronous implementation of the virtual data mover +interface. + +When the future is polled for the first time the data mover operation will be executed +synchronously on the same thread that polled the future. + +To create a new synchronous data mover instance, use **data_mover_sync_new**(3) function. + +Synchronous data mover supports following operations: + +* **vdm_memcpy**(3) - memory copy operation + +Synchronous data mover does not support notifier feature. For more information about +notifiers, see **miniasync_future**(7). + +For more information about the usage of thread data mover API, see *examples* directory +in miniasync repository . + +# EXAMPLE # + +Example usage of synchronous data mover **vdm_memcpy**(3) operation: +```c +struct data_mover_sync *dms = data_mover_sync_new(); +struct vdm *sync_mover = data_mover_sync_get_vdm(dms); +struct vdm_memcpy_future memcpy_fut = + vdm_memcpy(sync_mover, dest, src, copy_size, 0); +``` + +# SEE ALSO # + + **data_mover_sync_new**(3), **data_mover_sync_get_vdm**(3), + **vdm_memcpy**(3), **miniasync**(7), **miniasync_future**(7), + **miniasync_vdm**(7) and **** diff --git a/doc/miniasync_vdm_threads.3.md.in b/doc/miniasync_vdm_threads.3.md.in deleted file mode 100644 index 1a1075c6472..00000000000 --- a/doc/miniasync_vdm_threads.3.md.in +++ /dev/null @@ -1,82 +0,0 @@ ---- -layout: manual -Content-Style: 'text/css' -title: _MP(MINIASYNC_VDM_THREADS, 3) -collection: miniasync -header: MINIASYNC_VDM_THREADS -secondary_title: miniasync -... - -[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) -[comment]: <> (Copyright 2022, Intel Corporation) - -[comment]: <> (miniasync_vdm_threads.3 -- man page for miniasync vdm threads mover API) - -[NAME](#name)
-[SYNOPSIS](#synopsis)
-[DESCRIPTION](#description)
-[RETURN VALUE](#return-value)
-[SEE ALSO](#see-also)
- - -# NAME # - -**miniasync_vdm_threads** - Virtual data mover for miniasync using system threads - - -# SYNOPSIS # - -```c -#include - -struct vdm_descriptor *vdm_descriptor_threads(void); -struct vdm_descriptor *vdm_descriptor_threads_polled(void); -``` - -For general description of miniasync see **miniasync**(7). - - -# DESCRIPTION # - -In order to use parallel memcpy on system threads, create an appropriate -descriptor: -```c -struct vdm_descriptor *vdm_async_descriptor = vdm_descriptor_threads(); -``` -Then, create a new virtual data mover instance using this descriptor: -```c -struct vdm *vdm = vdm_new(vdm_async_descriptor); -``` -The next step is creating a future that will handle the memcpy operation: -```c -struct vdm_memcpy_future fut = vdm_memcpy(vdm, dst, src, size, flags); -``` -Now, during **runtime_wait**(3) or **runtime_wait_multiple**(3) this future will be polled -as long as it is not complete i.e. its state is not `FUTURE_STATE_COMPLETE`. -When this kind of future is polled and it is in state `FUTURE_STATE_IDLE`, -it tries to add its memcpy data into a queue of pending operations -that is watched by worker threads. If the memcpy data was added to the queue -successfully, the state of the future is set to `FUTURE_STATE_RUNNING`, -which guarantees that a worker thread will perform this operation. Otherwise, -the state is set to `FUTURE_STATE_IDLE` and whole process is repeated in a -next poll of this future. Polling a future in state `FUTURE_STATE_RUNNING` is just -a check if it's complete, so if it is - its state is set to `FUTURE_STATE_COMPLETE`, -otherwise it is still `FUTURE_STATE_RUNNING`. Memcpy operations are processed in -order in which they are put into the queue, but we cannot guarantee that they will -be processed in the same order as they are in the array of futures passed to -**runtime_wait_multiple**(3) if the count of operations is bigger than size of the queue. - -```c -struct vdm_descriptor *vdm_async_descriptor = vdm_descriptor_threads_polled(); -``` -: XXX add description for vdm_descriptor_threads_polled - -# RETURN VALUE # - -The **vdm_descriptor_threads** returns a pointer to `struct vdm_descriptor` -describing virtual data mover using system threads. - -# SEE ALSO # - -**miniasync**(7), **miniasync_future**(3), **miniasync_runtime**(3), **miniasync_vdm**(3), **runtime_wait**(3), -**runtime_wait_multiple**(3), **vdm_memcpy**(3), **vdm_new**(3) and **** diff --git a/doc/miniasync_vdm_threads.7.md b/doc/miniasync_vdm_threads.7.md new file mode 100644 index 00000000000..ce07fa4d543 --- /dev/null +++ b/doc/miniasync_vdm_threads.7.md @@ -0,0 +1,81 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(MINIASYNC_VDM_THREADS, 7) +collection: miniasync +header: MINIASYNC_VDM_THREADS +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (miniasync_vdm_threads.7 -- man page for miniasync vdm threads mover API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[EXAMPLE](#example)
+[SEE ALSO](#see-also)
+ +# NAME # + +**miniasync_vdm_threads** - virtual data mover implementation for miniasync using +system threads + +# SYNOPSIS # + +```c +#include +``` + +For general description of virtual data mover API, see **miniasync**(7). + +# DESCRIPTION # + +Thread data mover is a thread-based implementation of the virtual data mover. +Operations submitted to a thread data mover instance are queued and then executed +by one of the working threads that has taken an operation off the queue. Working threads +of each thread data mover instance are put to sleep until there's a data mover operation +to execute. + +When the future is polled for the first time the data mover operation will be queued +for asynchronous execution on one of the working threads associated with the instance +of thread data mover. + +Each thread data mover instance uses an internal ringbuffer for allocations associated with +data mover operations. + +To create a new thread data mover instance, use **data_mover_threads_new**(3) or +**data_mover_threads_default**(3) function. + +Thread data mover supports following operations: + +* **vdm_memcpy**(3) - memory copy operation + +Thread data mover supports following notifer types: + +* **FUTURE_NOTIFIER_NONE** - no notifier +* **FUTURE_NOTIFIER_WAKER** - waker + +For more information about notifiers, see **miniasync_future**(7). + +For more information about the usage of thread data mover API, see *examples* directory +in miniasync repository . + +# EXAMPLE # + +Example usage of default thread data mover **vdm_memcpy**(3) operation: +```c +struct data_mover_threads *dmt = data_mover_threads_default(); +struct vdm *thread_mover = data_mover_threads_get_vdm(dmt); +struct vdm_memcpy_future memcpy_fut = + vdm_memcpy(thread_mover, dest, src, copy_size, 0); +``` + +# SEE ALSO # + +**data_mover_threads_default**(3), **data_mover_threads_get_vdm**(3), +**data_mover_threads_new**(3), **vdm_memcpy**(3), +**miniasync**(7), **miniasync_future**(7), +**miniasync_vdm**(7) and **** diff --git a/doc/runtime_new.3.md b/doc/runtime_new.3.md new file mode 100644 index 00000000000..681947facd4 --- /dev/null +++ b/doc/runtime_new.3.md @@ -0,0 +1,55 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(RUNTIME_NEW, 3) +collection: miniasync +header: RUNTIME_NEW +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (runtime_new.3 -- man page for miniasync runtime_new operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**runtime_new**(), **runtime_delete**() - allocate or free runtime structure + +# SYNOPSIS # + +```c +#include + +struct runtime; + +struct runtime *runtime_new(void); +void runtime_delete(struct runtime *runtime); +``` + +For general description of runtime API, see **miniasync_runtime**(7). + +# DESCRIPTION # + +The **runtime_new**() function allocates and initializes a new runtime structure. +Runtime can be used for optimized future polling. + +The **runtime_delete**() function frees and finalizes the runtime structure pointed +by *runtime*. + +## RETURN VALUE ## + +The **runtime_new**() function returns a pointer to new *struct runtime* structure +or a *NULL* if the allocation or initialization of *struct runtime* failed. + +The **runtime_delete**() function does not return any value. + +# SEE ALSO # + +**miniasync**(7), **miniasync_runtime**(3) and **** diff --git a/doc/runtime_wait.3.md b/doc/runtime_wait.3.md new file mode 100644 index 00000000000..bc0426b568e --- /dev/null +++ b/doc/runtime_wait.3.md @@ -0,0 +1,69 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(RUNTIME_WAIT, 3) +collection: miniasync +header: RUNTIME_WAIT +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (runtime_wait.3 -- man page for miniasync runtime API) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**runtime_wait**(), **runtime_wait_multiple**() - wait for the completion of single +or multiple futures + +# SYNOPSIS # + +```c +#include + +struct future { + future_task_fn task; + struct future_context context; +}; + +struct runtime; + +void runtime_wait(struct runtime *runtime, struct future *fut); +void runtime_wait_multiple(struct runtime *runtime, struct future *futs[], + size_t nfuts); +``` + +For general description of runtime API, see **miniasync_runtime**(7). + +# DESCRIPTION # + +The **runtime_wait**() function blocks the calling thread until the future structure +pointed by *fut* completes. While waiting the calling thread repeatedly polls the +future with **future_poll**(3) function until completion. + +The **runtime_wait_multiple**() function works similar to the **runtime_wait**() function, +additionally it facilitates polling of multiple futures in an array. **runtime_wait_multiple**() +function uniformly polls the first *nfuts* futures in the array pointed by *futs* until all +of them complete execution. + +**miniasync**(7) runtime implementation makes use of the waker notifier feature to optimize +future polling. For more information about the waker feature, see **miniasync_future**(7). + +## RETURN VALUE ## + +The **runtime_wait**() function returns a pointer to a new runtime structure. + +The **runtime_wait_multiple**() function does not return any value. + +# SEE ALSO # + +**future_poll**(3), **miniasync**(7), +**miniasync_future**(7) **miniasync_runtime**(7) +and **** diff --git a/doc/vdm_memcpy.3.md b/doc/vdm_memcpy.3.md new file mode 100644 index 00000000000..15b237ed37d --- /dev/null +++ b/doc/vdm_memcpy.3.md @@ -0,0 +1,85 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(VDM_MEMCPY, 3) +collection: miniasync +header: VDM_MEMCPY +secondary_title: miniasync +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2022, Intel Corporation) + +[comment]: <> (vdm_memcpy.3 -- man page for miniasync vdm_memcpy operation) + +[NAME](#name)
+[SYNOPSIS](#synopsis)
+[DESCRIPTION](#description)
+[RETURN VALUE](#return-value)
+[SEE ALSO](#see-also)
+ +# NAME # + +**vdm_memcpy**() - create a new memcpy virtual data mover operation structure + +# SYNOPSIS # + +```c +#include + +struct vdm { + vdm_operation_new op_new; + vdm_operation_delete op_delete; + vdm_operation_start op_start; + vdm_operation_check op_check; +}; + +enum vdm_operation_type { + VDM_OPERATION_MEMCPY, +}; + +struct vdm_operation_output_memcpy { + void *dest; +}; + +struct vdm_operation_data { + void *op; + struct vdm *vdm; +}; + +struct vdm_operation_output { + enum vdm_operation_type type; + union { + struct vdm_operation_output_memcpy memcpy; + } output; +}; + +FUTURE(vdm_operation_future, + struct vdm_operation_data, struct vdm_operation_output); + +struct vdm_operation_future vdm_memcpy(struct vdm *vdm, void *dest, void *src, + size_t n, uint64_t flags); +``` + +For general description of virtual data mover API, see **miniasync_vdm**(7). + +# DESCRIPTION # + +**vdm_memcpy**() initializes and returns a new memcpy future based on the virtual data mover +implementation instance *vdm*. The parameters: *dest*, *src*, *n* are standard memcpy parameters. +The *flags* represents data mover specific flags. For example, **miniasync_vdm_dml**(7) flag +**MINIASYNC_DML_F_MEM_DURABLE** specifies that the write destination is identified as a write +to durable memory. This flag is meant to be used only with the **miniasync_vdm_dml**(7) data mover +implementation, providing it to any other data mover will result in undefined behavior. + +Memcpy future obtained using **vdm_memcpy**() will attempt to copy *n* bytes from memory area +*src* to memory area *dest* when its polled. + +## RETURN VALUE ## + +The **vdm_memcpy**() function returns an initialized *struct vdm_operation_future* memcpy future. + +# SEE ALSO # + +**miniasync**(7), **miniasync_vdm**(7), +**miniasync_vdm_dml**(7) and **** diff --git a/examples/basic-async/basic-async.c b/examples/basic-async/basic-async.c index 9a9e1adadc4..5bbb20d0fcc 100644 --- a/examples/basic-async/basic-async.c +++ b/examples/basic-async/basic-async.c @@ -8,9 +8,47 @@ #define TEST_SIZE 1024 +int src_dst_new(char **src1, char **dst1, char **src2, char **dst2) { + size_t size = TEST_SIZE * sizeof(char); + *src1 = malloc(size); + if (*src1 == NULL) + return 1; + + *dst1 = malloc(size); + if (*dst1 == NULL) + goto end_1; + + *src2 = malloc(size * 2); + if (*src2 == NULL) + goto end_2; + + *dst2 = malloc(size * 2); + if (*dst2 == NULL) + goto end_3; + + return 0; + +end_3: + free(*src2); +end_2: + free(*dst1); +end_1: + free(*src1); + + return 1; +} + +void src_dst_del(char **src1, char **dst1, char **src2, char **dst2) { + free(*src1); + free(*src2); + free(*dst1); + free(*dst2); +} + int main(void) { + int ret = 0; /* * First, we have to create a runner instance, get descriptor for * asynchronous memcpy which is vdm_descriptor_threads and @@ -31,18 +69,15 @@ main(void) * after another. In this example we call two unique memcpy * operations in a loop. */ + char *src1; + char *dst1; + char *src2; + char *dst2; + for (int i = 0; i < 2; i++) { - char *src1 = malloc(TEST_SIZE * sizeof(char)); - char *dst1 = malloc(TEST_SIZE * sizeof(char)); - char *src2 = malloc(TEST_SIZE * 2 * sizeof(char)); - char *dst2 = malloc(TEST_SIZE * 2 * sizeof(char)); - if (src1 == NULL || dst1 == NULL || - src2 == NULL || dst2 == NULL) { - fprintf(stderr, "Failed to allocate memory.\n"); - runtime_delete(r); - data_mover_threads_delete(dmt); - return 1; - } + ret = src_dst_new(&src1, &dst1, &src2, &dst2); + if (ret) + goto end; memset(src1, 7, TEST_SIZE); memset(src2, 6, TEST_SIZE * 2); @@ -67,10 +102,7 @@ main(void) */ runtime_wait_multiple(r, futs, 2); - free(src1); - free(src2); - free(dst1); - free(dst2); + src_dst_del(&src1, &dst1, &src2, &dst2); } /* @@ -80,7 +112,8 @@ main(void) * which is freed only by vdm_delete or at end of execution of a process * that called vdm_new. */ +end: data_mover_threads_delete(dmt); runtime_delete(r); - return 0; + return ret; } diff --git a/examples/basic/basic.c b/examples/basic/basic.c index 4a023d8c3f9..62ed64295e6 100644 --- a/examples/basic/basic.c +++ b/examples/basic/basic.c @@ -81,7 +81,7 @@ memcpy_to_print_map(struct future_context *memcpy_ctx, struct async_print_data *print = future_context_get_data(print_ctx); assert(output->type == VDM_OPERATION_MEMCPY); - print->value = output->memcpy.dest; + print->value = output->output.memcpy.dest; assert(arg == (void *)0xd); } @@ -120,6 +120,7 @@ main(void) char *buf_b = malloc(otherbuf_size + 1); if (buf_b == NULL) { fprintf(stderr, "Failed to create buf_b\n"); + free(buf_a); return 1; } @@ -131,6 +132,8 @@ main(void) struct data_mover_threads *dmt = data_mover_threads_default(); if (dmt == NULL) { fprintf(stderr, "Failed to allocate data mover.\n"); + free(buf_a); + free(buf_b); runtime_delete(r); return 1; } diff --git a/extras/dml/CMakeLists.txt b/extras/dml/CMakeLists.txt index d3a119bb589..739fefc3918 100644 --- a/extras/dml/CMakeLists.txt +++ b/extras/dml/CMakeLists.txt @@ -3,20 +3,20 @@ # Copyright 2021-2022, Intel Corporation # -project(miniasync-dml C) +project(miniasync-vdm-dml C) -add_cstyle(miniasync-dml +add_cstyle(miniasync-vdm-dml ${CMAKE_CURRENT_SOURCE_DIR}/*.[ch] ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/libminiasync-dml/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/libminiasync-vdm-dml/*.h ${CMAKE_CURRENT_SOURCE_DIR}/utils/*.[ch]) -add_check_whitespace(miniasync-dml +add_check_whitespace(miniasync-vdm-dml ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/*.[ch] ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/libminiasync-dml/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/libminiasync-vdm-dml/*.h ${CMAKE_CURRENT_SOURCE_DIR}/utils/*.[ch]) set(DML_SOURCES @@ -31,24 +31,24 @@ set(DML_CORE_DEPS ${CORE_SOURCE_DIR}/util.c ${CORE_SOURCE_DIR}/util_posix.c) -add_library(miniasync-dml SHARED ${DML_SOURCES} ${DML_CORE_DEPS}) +add_library(miniasync-vdm-dml SHARED ${DML_SOURCES} ${DML_CORE_DEPS}) -target_include_directories(miniasync-dml PRIVATE . +target_include_directories(miniasync-vdm-dml PRIVATE . ${MINIASYNC_DML_INCLUDE_DIR} ${MINIASYNC_INCLUDE_DIR} ${MINIASYNC_SOURCE_DIR}) -set_target_properties(miniasync-dml PROPERTIES - PUBLIC_HEADER ${MINIASYNC_DML_INCLUDE_DIR}/libminiasync-dml.h +set_target_properties(miniasync-vdm-dml PROPERTIES + PUBLIC_HEADER ${MINIASYNC_DML_INCLUDE_DIR}/libminiasync-vdm-dml.h ) -install(TARGETS miniasync-dml +install(TARGETS miniasync-vdm-dml PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # Install headers included in public header -install(DIRECTORY ${MINIASYNC_DML_INCLUDE_DIR}/libminiasync-dml +install(DIRECTORY ${MINIASYNC_DML_INCLUDE_DIR}/libminiasync-vdm-dml DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" ) diff --git a/extras/dml/README.md b/extras/dml/README.md index e40fc6b0e08..11e28bffacb 100644 --- a/extras/dml/README.md +++ b/extras/dml/README.md @@ -1,14 +1,16 @@ -This directory contains DML implementation *miniasync* library (*miniasync-dml* -library). +This directory contains **miniasync-vdm-dml** library, a library encapsulating **DML** +implementation of the **miniasync_vdm** virtual data mover. -The DML library is required to compile *miniasync-dml* library. -By default DML compiles with software path only. If you want to make use of -hardware path, make sure that DML is installed with ```DML_HW``` option. +The *Data Mover Library* (**DML**) is required to compile **miniasync-vdm-dml** library. +By default **DML** compiles with software path only. If you want to make use of +hardware path, make sure that DML is installed with **DML_HW** option. -By default, *miniasync-dml* mover performs operations using software path. -To perform operation with hardware path use *MINIASYNC_DML_F_PATH_HW* flag. +**DML** data mover supports offloading certain computations to the hardware +accelerators (e.g. Intel® Data Streaming Accelerator). To use this feature, make +sure that **DML** library is compiled with **DML_HW** option. +For more information about **DML**, see [DML](https://github.com/intel/DML). -Compiling *miniasync-dml*: +Compiling *miniasync-vdm-dml*: ```shell $ cmake .. -DCOMPILE_DML=ON ``` diff --git a/extras/dml/data_mover_dml.c b/extras/dml/data_mover_dml.c index 30fb5d730f6..4a10bba3cba 100644 --- a/extras/dml/data_mover_dml.c +++ b/extras/dml/data_mover_dml.c @@ -7,7 +7,7 @@ #include #include "core/membuf.h" -#include "libminiasync-dml.h" +#include "libminiasync-vdm-dml.h" #include "core/out.h" #include "core/util.h" @@ -18,7 +18,7 @@ struct data_mover_dml { }; /* - * data_mover_dml_translate_flags -- translate miniasync-dml flags + * data_mover_dml_translate_flags -- translate miniasync-vdm-dml flags */ static void data_mover_dml_translate_flags(uint64_t flags, uint64_t *dml_flags, @@ -120,8 +120,10 @@ data_mover_dml_operation_new(struct vdm *vdm, switch (operation->type) { case VDM_OPERATION_MEMCPY: return data_mover_dml_memcpy_job_new(vdm_dml, - operation->memcpy.dest, operation->memcpy.src, - operation->memcpy.n, operation->memcpy.flags); + operation->data.memcpy.dest, + operation->data.memcpy.src, + operation->data.memcpy.n, + operation->data.memcpy.flags); default: ASSERT(0); /* unreachable */ } @@ -139,13 +141,16 @@ data_mover_dml_operation_delete(void *op, struct vdm_operation_output *output) switch (job->operation) { case DML_OP_MEM_MOVE: output->type = VDM_OPERATION_MEMCPY; - output->memcpy.dest = job->destination_first_ptr; + output->output.memcpy.dest = + job->destination_first_ptr; break; default: ASSERT(0); } data_mover_dml_memcpy_job_delete(&job); + + membuf_free(op); } /* @@ -178,32 +183,6 @@ data_mover_dml_operation_start(void *op, struct future_notifier *n) return 0; } -/* - * data_mover_dml_membuf_check -- returns the status of the dml job - */ -enum membuf_check_result -data_mover_dml_membuf_check(void *ptr, void *data) -{ - switch (data_mover_dml_operation_check(ptr)) { - case FUTURE_STATE_COMPLETE: - return MEMBUF_PTR_CAN_REUSE; - case FUTURE_STATE_RUNNING: - return MEMBUF_PTR_CAN_WAIT; - case FUTURE_STATE_IDLE: - return MEMBUF_PTR_IN_USE; - } - ASSERT(0); -} - -/* - * data_mover_dml_membuf_size -- returns the size of a dml job - */ -static size_t -data_mover_dml_membuf_size(void *ptr, void *data) -{ - return sizeof(dml_job_t); -} - /* * data_mover_dml_vdm -- dml asynchronous memcpy */ @@ -224,8 +203,7 @@ data_mover_dml_new(void) if (vdm_dml == NULL) return NULL; - vdm_dml->membuf = membuf_new(data_mover_dml_membuf_check, - data_mover_dml_membuf_size, NULL, vdm_dml); + vdm_dml->membuf = membuf_new(vdm_dml); vdm_dml->base = data_mover_dml_vdm; return vdm_dml; diff --git a/extras/dml/include/libminiasync-dml.h b/extras/dml/include/libminiasync-vdm-dml.h similarity index 62% rename from extras/dml/include/libminiasync-dml.h rename to extras/dml/include/libminiasync-vdm-dml.h index 230b75de445..d553d147501 100644 --- a/extras/dml/include/libminiasync-dml.h +++ b/extras/dml/include/libminiasync-vdm-dml.h @@ -2,16 +2,17 @@ /* Copyright 2021-2022, Intel Corporation */ /* - * libminiasync-dml.h -- definition of miniasync dml implementation + * libminiasync-vdm-dml.h -- definition of miniasync dml data mover + * implementation */ -#ifndef MINIASYNC_DML_H -#define MINIASYNC_DML_H 1 +#ifndef MINIASYNC_VDM_DML_H +#define MINIASYNC_VDM_DML_H 1 #include #include -#include "libminiasync-dml/data_mover_dml.h" +#include "libminiasync-vdm-dml/data_mover_dml.h" #ifdef __cplusplus extern "C" { @@ -27,4 +28,4 @@ extern "C" { } #endif -#endif /* MINIASYNC_DML_H */ +#endif /* MINIASYNC_VDM_DML_H */ diff --git a/extras/dml/include/libminiasync-dml/data_mover_dml.h b/extras/dml/include/libminiasync-vdm-dml/data_mover_dml.h similarity index 100% rename from extras/dml/include/libminiasync-dml/data_mover_dml.h rename to extras/dml/include/libminiasync-vdm-dml/data_mover_dml.h diff --git a/extras/dml/utils/util_dml.h b/extras/dml/utils/util_dml.h index e2e0bcc09b1..6d607acca4a 100644 --- a/extras/dml/utils/util_dml.h +++ b/extras/dml/utils/util_dml.h @@ -2,7 +2,7 @@ /* Copyright 2022, Intel Corporation */ /* - * util_dml -- utils for miniasync-dml + * util_dml -- utils for miniasync-vdm-dml */ #ifndef UTIL_DML_H diff --git a/src/core/membuf.c b/src/core/membuf.c index f83fddfc8a1..8b427eab054 100644 --- a/src/core/membuf.c +++ b/src/core/membuf.c @@ -32,12 +32,15 @@ struct membuf { struct threadbuf *tbuf_unused_first; /* list of threadbufs for reuse */ os_tls_key_t bufkey; /* TLS key for threadbuf */ - membuf_ptr_check check_func; /* object state check function */ - membuf_ptr_size size_func; /* object size function */ - void *func_data; /* user-provided function argument */ void *user_data; /* user-provided buffer data */ }; +struct membuf_entry { + int32_t allocated; /* 1 - allocated, 0 - unused */ + uint32_t size; /* size of the entry */ + char data[]; /* user data */ +}; + /* * membuf_key_destructor -- thread destructor for threadbuf */ @@ -64,17 +67,13 @@ membuf_key_destructor(void *data) * membuf_new -- allocates and initializes a new membuf instance */ struct membuf * -membuf_new(membuf_ptr_check check_func, membuf_ptr_size size_func, - void *func_data, void *user_data) +membuf_new(void *user_data) { struct membuf *membuf = malloc(sizeof(struct membuf)); if (membuf == NULL) return NULL; membuf->user_data = user_data; - membuf->check_func = check_func; - membuf->size_func = size_func; - membuf->func_data = func_data; membuf->tbuf_first = NULL; membuf->tbuf_unused_first = NULL; os_mutex_init(&membuf->lists_lock); @@ -100,6 +99,34 @@ membuf_delete(struct membuf *membuf) free(membuf); } +/* + * membuf_entry_get_size -- returns the size of an entry + */ +static size_t +membuf_entry_get_size(void *real_ptr) +{ + struct membuf_entry *entry = real_ptr; + + uint32_t size; + util_atomic_load_explicit32(&entry->size, &size, memory_order_acquire); + + return size; +} + +/* + * membuf_entry_is_allocated -- checks whether the entry is allocated + */ +static int +membuf_entry_is_allocated(void *real_ptr) +{ + struct membuf_entry *entry = real_ptr; + int32_t allocated; + util_atomic_load_explicit32(&entry->allocated, + &allocated, memory_order_acquire); + + return allocated; +} + /* * membuf_get_threadbuf -- returns thread-local buffer for allocations */ @@ -147,7 +174,7 @@ membuf_get_threadbuf(struct membuf *membuf) /* * membuf_threadbuf_prune -- reclaims available buffer space */ -static int +static void membuf_threadbuf_prune(struct membuf *membuf, struct threadbuf *tbuf) { @@ -165,20 +192,11 @@ membuf_threadbuf_prune(struct membuf *membuf, /* check the next object after the available memory */ size_t next_loc = (tbuf->offset + tbuf->available) % tbuf->size; void *next = &tbuf->buf[next_loc]; - switch (membuf->check_func(next, membuf->func_data)) { - case MEMBUF_PTR_CAN_REUSE: { - size_t s = membuf->size_func(next, - membuf->func_data); - tbuf->available += s; - } break; - case MEMBUF_PTR_CAN_WAIT: - return 0; - case MEMBUF_PTR_IN_USE: - return -1; - } - } + if (membuf_entry_is_allocated(next)) + return; - return 0; + tbuf->available += membuf_entry_get_size(next); + } } /* @@ -191,32 +209,50 @@ membuf_alloc(struct membuf *membuf, size_t size) if (tbuf == NULL) return NULL; - if (size > tbuf->size) + size_t real_size = size + sizeof(struct membuf_entry); + + if (real_size > tbuf->size) return NULL; - if (tbuf->offset + size > tbuf->size) { + if (tbuf->offset + real_size > tbuf->size) { tbuf->leftovers = tbuf->available; tbuf->offset = 0; tbuf->available = 0; } /* wait until enough memory becomes available */ - while (size > tbuf->available) { - if (membuf_threadbuf_prune(membuf, tbuf) < 0) { - /* - * Fail if not enough space was reclaimed and no - * memory is available for further reclamation. - */ - if (size > tbuf->available) - return NULL; - } + if (real_size > tbuf->available) { + membuf_threadbuf_prune(membuf, tbuf); + /* + * Fail if not enough space was reclaimed and no + * memory is available for further reclamation. + */ + if (real_size > tbuf->available) + return NULL; } size_t pos = tbuf->offset; - tbuf->offset += size; - tbuf->available -= size; + tbuf->offset += real_size; + tbuf->available -= real_size; + + struct membuf_entry *entry = (struct membuf_entry *)&tbuf->buf[pos]; + entry->size = (uint32_t)real_size; + entry->allocated = 1; + + return &entry->data; +} + +/* + * membuf_free -- deallocates an entry + */ +void +membuf_free(void *ptr) +{ + struct membuf_entry *entry = (struct membuf_entry *) + ((uintptr_t)ptr - sizeof(struct membuf_entry)); - return &tbuf->buf[pos]; + util_atomic_store_explicit64(&entry->allocated, 0, + memory_order_release); } /* diff --git a/src/core/membuf.h b/src/core/membuf.h index adb2ef3f220..e85264373cc 100644 --- a/src/core/membuf.h +++ b/src/core/membuf.h @@ -4,8 +4,8 @@ /* * membuf.h -- definitions for "membuf" module. * - * Membuf is a circular object buffer with automatic reclamation. Each instance - * uses an internal per-thread buffer to avoid heavyweight synchronization. + * Membuf is a circular object buffer. Each instance uses an internal + * per-thread buffer to avoid heavyweight synchronization. * * Allocation is linear and very cheap. The expectation is that objects within * the buffer will be reclaimable long before the linear allocator might need @@ -19,34 +19,11 @@ struct membuf; -enum membuf_check_result { - /* - * Cannot reclaim memory object, alloc will fail. This should be used - * when object is owned by the current working thread. - */ - MEMBUF_PTR_IN_USE, - - /* - * Cannot reclaim memory object, alloc will busy-poll. This should be - * used when object is being processed in the background. - */ - MEMBUF_PTR_CAN_WAIT, - - /* - * Can reclaim memory object, alloc will reuse memory. - */ - MEMBUF_PTR_CAN_REUSE, -}; - -typedef enum membuf_check_result (*membuf_ptr_check)(void *ptr, void *data); -typedef size_t (*membuf_ptr_size)(void *ptr, void *data); - -struct membuf *membuf_new(membuf_ptr_check check_func, - membuf_ptr_size size_func, - void *func_data, void *user_data); +struct membuf *membuf_new(void *user_data); void membuf_delete(struct membuf *membuf); void *membuf_alloc(struct membuf *membuf, size_t size); +void membuf_free(void *ptr); void *membuf_ptr_user_data(void *ptr); diff --git a/src/core/os.h b/src/core/os.h index e26b0636392..b3c0b3518a5 100644 --- a/src/core/os.h +++ b/src/core/os.h @@ -66,16 +66,6 @@ struct iovec; #define OS_LOCK_NB 4 #define OS_LOCK_UN 8 -#ifndef _WIN32 -typedef struct stat os_stat_t; -#define os_fstat fstat -#define os_lseek lseek -#else -typedef struct _stat64 os_stat_t; -#define os_fstat _fstat64 -#define os_lseek _lseeki64 -#endif - #define os_close close #define os_fclose fclose @@ -85,14 +75,8 @@ typedef off_t os_off_t; /* XXX: os_off_t defined in platform.h */ #endif int os_open(const char *pathname, int flags, ...); -int os_fsync(int fd); -int os_fsync_dir(const char *dir_name); -int os_stat(const char *pathname, os_stat_t *buf); int os_unlink(const char *pathname); -int os_access(const char *pathname, int mode); FILE *os_fopen(const char *pathname, const char *mode); -FILE *os_fdopen(int fd, const char *mode); -int os_chmod(const char *pathname, mode_t mode); int os_mkstemp(char *temp); int os_ftruncate(int fd, os_off_t length); int os_flock(int fd, int operation); @@ -103,7 +87,6 @@ int os_unsetenv(const char *name); int os_setenv(const char *name, const char *value, int overwrite); char *os_getenv(const char *name); const char *os_strsignal(int sig); -int os_execv(const char *path, char *const argv[]); /* * XXX: missing APis (used in ut_file.c) diff --git a/src/core/os_posix.c b/src/core/os_posix.c index 12bce9572d7..6c3142b51e6 100644 --- a/src/core/os_posix.c +++ b/src/core/os_posix.c @@ -52,41 +52,6 @@ os_open(const char *pathname, int flags, ...) } } -/* - * os_fsync -- fsync abstraction layer - */ -int -os_fsync(int fd) -{ - return fsync(fd); -} - -/* - * os_fsync_dir -- fsync the directory - */ -int -os_fsync_dir(const char *dir_name) -{ - int fd = os_open(dir_name, O_RDONLY | O_DIRECTORY); - if (fd < 0) - return -1; - - int ret = os_fsync(fd); - - os_close(fd); - - return ret; -} - -/* - * os_stat -- stat abstraction layer - */ -int -os_stat(const char *pathname, os_stat_t *buf) -{ - return stat(pathname, buf); -} - /* * os_unlink -- unlink abstraction layer */ @@ -96,15 +61,6 @@ os_unlink(const char *pathname) return unlink(pathname); } -/* - * os_access -- access abstraction layer - */ -int -os_access(const char *pathname, int mode) -{ - return access(pathname, mode); -} - /* * os_fopen -- fopen abstraction layer */ @@ -114,24 +70,6 @@ os_fopen(const char *pathname, const char *mode) return fopen(pathname, mode); } -/* - * os_fdopen -- fdopen abstraction layer - */ -FILE * -os_fdopen(int fd, const char *mode) -{ - return fdopen(fd, mode); -} - -/* - * os_chmod -- chmod abstraction layer - */ -int -os_chmod(const char *pathname, mode_t mode) -{ - return chmod(pathname, mode); -} - /* * os_mkstemp -- mkstemp abstraction layer */ @@ -245,9 +183,3 @@ os_strsignal(int sig) { return strsignal(sig); } - -int -os_execv(const char *path, char *const argv[]) -{ - return execv(path, argv); -} diff --git a/src/core/os_windows.c b/src/core/os_windows.c index 8c08fb16d50..7d3d7f711b5 100644 --- a/src/core/os_windows.c +++ b/src/core/os_windows.c @@ -35,6 +35,11 @@ * os_windows.c -- windows abstraction layer */ +/* disable conditional expression is const warning */ +#ifdef _WIN32 +#pragma warning(disable : 4127) +#endif + #define _CRT_RAND_S #include @@ -90,57 +95,6 @@ os_open(const char *pathname, int flags, ...) return ret; } -/* - * os_fsync -- fsync abstraction layer - */ -int -os_fsync(int fd) -{ - HANDLE handle = (HANDLE) _get_osfhandle(fd); - - if (handle == INVALID_HANDLE_VALUE) { - errno = EBADF; - return -1; - } - - if (!FlushFileBuffers(handle)) { - errno = EINVAL; - return -1; - } - - return 0; -} - -/* - * os_fsync_dir -- fsync the directory - */ -int -os_fsync_dir(const char *dir_name) -{ - /* to avoid unused formal parameter warning */ - SUPPRESS_UNUSED(dir_name); - - /* XXX not used and not implemented */ - ASSERT(0); - return -1; -} - -/* - * os_stat -- stat abstraction layer - */ -int -os_stat(const char *pathname, os_stat_t *buf) -{ - wchar_t *path = util_toUTF16(pathname); - if (path == NULL) - return -1; - - int ret = _wstat64(path, buf); - - util_free_UTF16(path); - return ret; -} - /* * os_unlink -- unlink abstraction layer */ @@ -156,21 +110,6 @@ os_unlink(const char *pathname) return ret; } -/* - * os_access -- access abstraction layer - */ -int -os_access(const char *pathname, int mode) -{ - wchar_t *path = util_toUTF16(pathname); - if (path == NULL) - return -1; - - int ret = _waccess(path, mode); - util_free_UTF16(path); - return ret; -} - /* * os_skipBOM -- (internal) Skip BOM in file stream * @@ -224,32 +163,6 @@ os_fopen(const char *pathname, const char *mode) return ret; } -/* - * os_fdopen -- fdopen abstraction layer - */ -FILE * -os_fdopen(int fd, const char *mode) -{ - FILE *ret = fdopen(fd, mode); - os_skipBOM(ret); - return ret; -} - -/* - * os_chmod -- chmod abstraction layer - */ -int -os_chmod(const char *pathname, mode_t mode) -{ - wchar_t *path = util_toUTF16(pathname); - if (path == NULL) - return -1; - - int ret = _wchmod(path, mode); - util_free_UTF16(path); - return ret; -} - /* * os_mkstemp -- generate a unique temporary filename from template */ @@ -606,46 +519,3 @@ os_strsignal(int sig) else return STR_UNKNOWN_SIGNAL; } - -int -os_execv(const char *path, char *const argv[]) -{ - wchar_t *wpath = util_toUTF16(path); - if (wpath == NULL) - return -1; - - int argc = 0; - while (argv[argc]) - argc++; - - int ret; - wchar_t **wargv = calloc(argc + 1, sizeof(wargv[0])); - if (!wargv) { - ret = -1; - goto wargv_alloc_failed; - } - - for (int i = 0; i < argc; ++i) { - wargv[i] = util_toUTF16(argv[i]); - if (!wargv[i]) { - ret = -1; - goto end; - } - } - - intptr_t iret = _wexecv(wpath, wargv); - if (iret == 0) - ret = 0; - else - ret = -1; - -end: - for (int i = 0; i < argc; ++i) - util_free_UTF16(wargv[i]); - free(wargv); - -wargv_alloc_failed: - util_free_UTF16(wpath); - - return ret; -} diff --git a/src/core/ringbuf.c b/src/core/ringbuf.c index 43445dd3635..d834d865b95 100644 --- a/src/core/ringbuf.c +++ b/src/core/ringbuf.c @@ -7,6 +7,11 @@ * waiting. */ +/* disable conditional expression is const warning */ +#ifdef _WIN32 +#pragma warning(disable : 4127) +#endif + #include "core/valgrind_internal.h" #include "ringbuf.h" @@ -31,7 +36,7 @@ /* avoid false sharing by padding the variable */ #define CACHELINE_PADDING(type, name)\ -union { type name; uint64_t name##_padding[8]; } +union { type name; uint64_t name##_padding[8]; } name##_padded struct ringbuf { CACHELINE_PADDING(uint64_t, read_pos); @@ -64,19 +69,19 @@ ringbuf_new(unsigned length) if (rbuf == NULL) return NULL; - if (os_semaphore_init(&rbuf->nfree, length)) { + if (os_semaphore_init(&rbuf->nfree_padded.nfree, length)) { free(rbuf); return NULL; } - if (os_semaphore_init(&rbuf->nused, 0)) { - util_semaphore_destroy(&rbuf->nfree); + if (os_semaphore_init(&rbuf->nused_padded.nused, 0)) { + util_semaphore_destroy(&rbuf->nfree_padded.nfree); free(rbuf); return NULL; } - rbuf->read_pos = 0; - rbuf->write_pos = 0; + rbuf->read_pos_padded.read_pos = 0; + rbuf->write_pos_padded.write_pos = 0; rbuf->len = length; rbuf->len_mask = length - 1; @@ -107,7 +112,8 @@ ringbuf_stop(struct ringbuf *rbuf) LOG(4, NULL); /* wait for the buffer to become empty */ - while (rbuf->read_pos != rbuf->write_pos) + while (rbuf->read_pos_padded.read_pos != + rbuf->write_pos_padded.write_pos) __sync_synchronize(); int ret = util_bool_compare_and_swap64(&rbuf->running, 1, 0); @@ -115,7 +121,7 @@ ringbuf_stop(struct ringbuf *rbuf) /* XXX just unlock all waiting threads somehow... */ for (int64_t i = 0; i < RINGBUF_MAX_CONSUMER_THREADS; ++i) - util_semaphore_post(&rbuf->nused); + util_semaphore_post(&rbuf->nused_padded.nused); } #endif @@ -127,9 +133,10 @@ ringbuf_delete(struct ringbuf *rbuf) { LOG(4, NULL); - ASSERTeq(rbuf->read_pos, rbuf->write_pos); - util_semaphore_destroy(&rbuf->nfree); - util_semaphore_destroy(&rbuf->nused); + ASSERTeq(rbuf->read_pos_padded.read_pos, + rbuf->write_pos_padded.write_pos); + util_semaphore_destroy(&rbuf->nfree_padded.nfree); + util_semaphore_destroy(&rbuf->nused_padded.nused); free(rbuf); } @@ -142,7 +149,8 @@ ringbuf_enqueue_atomic(struct ringbuf *rbuf, void *data) { LOG(4, NULL); - size_t w = util_fetch_and_add64(&rbuf->write_pos, 1) & rbuf->len_mask; + size_t w = util_fetch_and_add64(&rbuf->write_pos_padded.write_pos, 1) + & rbuf->len_mask; ASSERT(rbuf->running); @@ -168,11 +176,11 @@ ringbuf_enqueue(struct ringbuf *rbuf, void *data) { LOG(4, NULL); - util_semaphore_wait(&rbuf->nfree); + util_semaphore_wait(&rbuf->nfree_padded.nfree); ringbuf_enqueue_atomic(rbuf, data); - util_semaphore_post(&rbuf->nused); + util_semaphore_post(&rbuf->nused_padded.nused); return 0; } @@ -188,12 +196,12 @@ ringbuf_tryenqueue(struct ringbuf *rbuf, void *data) { LOG(4, NULL); - if (util_semaphore_trywait(&rbuf->nfree) != 0) + if (util_semaphore_trywait(&rbuf->nfree_padded.nfree) != 0) return -1; ringbuf_enqueue_atomic(rbuf, data); - util_semaphore_post(&rbuf->nused); + util_semaphore_post(&rbuf->nused_padded.nused); return 0; } @@ -206,7 +214,8 @@ ringbuf_dequeue_atomic(struct ringbuf *rbuf) { LOG(4, NULL); - size_t r = util_fetch_and_add64(&rbuf->read_pos, 1) & rbuf->len_mask; + size_t r = util_fetch_and_add64(&rbuf->read_pos_padded.read_pos, 1) + & rbuf->len_mask; /* * Again, in most cases, there won't be even a single loop, but if one * thread stalls while others perform work, it might happen that two @@ -234,14 +243,14 @@ ringbuf_dequeue(struct ringbuf *rbuf) { LOG(4, NULL); - util_semaphore_wait(&rbuf->nused); + util_semaphore_wait(&rbuf->nused_padded.nused); if (!rbuf->running) return NULL; void *data = ringbuf_dequeue_atomic(rbuf); - util_semaphore_post(&rbuf->nfree); + util_semaphore_post(&rbuf->nfree_padded.nfree); return data; } @@ -257,7 +266,7 @@ ringbuf_trydequeue(struct ringbuf *rbuf) { LOG(4, NULL); - if (util_semaphore_trywait(&rbuf->nused) != 0) + if (util_semaphore_trywait(&rbuf->nused_padded.nused) != 0) return NULL; if (!rbuf->running) @@ -265,7 +274,7 @@ ringbuf_trydequeue(struct ringbuf *rbuf) void *data = ringbuf_dequeue_atomic(rbuf); - util_semaphore_post(&rbuf->nfree); + util_semaphore_post(&rbuf->nfree_padded.nfree); return data; } diff --git a/src/core/util.h b/src/core/util.h index 85d8d2defa7..112db635493 100644 --- a/src/core/util.h +++ b/src/core/util.h @@ -97,7 +97,6 @@ extern unsigned long long Mmap_align; char *util_fgets(char *buffer, int max, FILE *stream); char *util_getexecname(char *path, size_t pathlen); char *util_part_realpath(const char *path); - int util_compare_file_inodes(const char *path1, const char *path2); int util_tmpfile(const char *dir, const char *templ, int flags); void *util_aligned_malloc(size_t alignment, size_t size); void util_aligned_free(void *ptr); diff --git a/src/core/util_posix.c b/src/core/util_posix.c index 467cbe53982..ab977b1bd5e 100644 --- a/src/core/util_posix.c +++ b/src/core/util_posix.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2015-2021, Intel Corporation */ +/* Copyright 2015-2022, Intel Corporation */ /* * util_posix.c -- Abstraction layer for misc utilities (Posix implementation) @@ -46,37 +46,6 @@ util_part_realpath(const char *path) return realpath(path, NULL); } -/* - * util_compare_file_inodes -- compare device and inodes of two files; - * this resolves hard links - */ -int -util_compare_file_inodes(const char *path1, const char *path2) -{ - struct stat sb1, sb2; - if (os_stat(path1, &sb1)) { - if (errno != ENOENT) { - ERR("!stat failed for %s", path1); - return -1; - } - LOG(1, "stat failed for %s", path1); - errno = 0; - return strcmp(path1, path2) != 0; - } - - if (os_stat(path2, &sb2)) { - if (errno != ENOENT) { - ERR("!stat failed for %s", path2); - return -1; - } - LOG(1, "stat failed for %s", path2); - errno = 0; - return strcmp(path1, path2) != 0; - } - - return sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino; -} - /* * util_tmpfile_mkstemp -- (internal) create temporary file * if O_TMPFILE not supported diff --git a/src/core/util_windows.c b/src/core/util_windows.c index 60737a11cc1..9dd414994c3 100644 --- a/src/core/util_windows.c +++ b/src/core/util_windows.c @@ -98,15 +98,6 @@ util_part_realpath(const char *path) return strdup(path); } -/* - * util_compare_file_inodes -- compare device and inodes of two files - */ -int -util_compare_file_inodes(const char *path1, const char *path2) -{ - return strcmp(path1, path2) != 0; -} - /* * util_tmpfile -- create a temporary file */ diff --git a/src/data_mover_sync.c b/src/data_mover_sync.c index c98d9df64b8..cd0fab42f0d 100644 --- a/src/data_mover_sync.c +++ b/src/data_mover_sync.c @@ -1,6 +1,11 @@ // SPDX-License-Identifier: BSD-3-Clause /* Copyright 2022, Intel Corporation */ +/* disable conditional expression is const warning */ +#ifdef _WIN32 +#pragma warning(disable : 4127) +#endif + #include "libminiasync/vdm.h" #include "core/membuf.h" #include "core/out.h" @@ -32,25 +37,6 @@ sync_operation_check(void *op) return complete ? FUTURE_STATE_COMPLETE : FUTURE_STATE_IDLE; } -/* - * sync_membuf_check -- checks the status of a sync job - */ -static enum membuf_check_result -sync_membuf_check(void *ptr, void *data) -{ - return sync_operation_check(ptr) == FUTURE_STATE_COMPLETE ? - MEMBUF_PTR_CAN_REUSE : MEMBUF_PTR_IN_USE; -} - -/* - * sync_membuf_size -- returns the size of a sync operation - */ -static size_t -sync_membuf_size(void *ptr, void *data) -{ - return sizeof(struct data_mover_sync_op); -} - /* * sync_operation_new -- creates a new sync operation */ @@ -79,11 +65,14 @@ sync_operation_delete(void *op, struct vdm_operation_output *output) switch (sync_op->op.type) { case VDM_OPERATION_MEMCPY: output->type = VDM_OPERATION_MEMCPY; - output->memcpy.dest = sync_op->op.memcpy.dest; + output->output.memcpy.dest = + sync_op->op.data.memcpy.dest; break; default: ASSERT(0); } + + membuf_free(op); } /* @@ -95,8 +84,9 @@ sync_operation_start(void *op, struct future_notifier *n) struct data_mover_sync_op *sync_op = (struct data_mover_sync_op *)op; if (n) n->notifier_used = FUTURE_NOTIFIER_NONE; - memcpy(sync_op->op.memcpy.dest, sync_op->op.memcpy.src, - sync_op->op.memcpy.n); + memcpy(sync_op->op.data.memcpy.dest, + sync_op->op.data.memcpy.src, + sync_op->op.data.memcpy.n); util_atomic_store_explicit32(&sync_op->complete, 1, memory_order_release); @@ -122,8 +112,7 @@ data_mover_sync_new(void) return NULL; dms->base = data_mover_sync_vdm; - dms->membuf = membuf_new(sync_membuf_check, sync_membuf_size, - NULL, dms); + dms->membuf = membuf_new(dms); if (dms->membuf == NULL) goto membuf_failed; diff --git a/src/data_mover_threads.c b/src/data_mover_threads.c index 0298a0c1e7e..5c209424084 100644 --- a/src/data_mover_threads.c +++ b/src/data_mover_threads.c @@ -1,6 +1,11 @@ // SPDX-License-Identifier: BSD-3-Clause /* Copyright 2022, Intel Corporation */ +/* disable conditional expression is const warning */ +#ifdef _WIN32 +#pragma warning(disable : 4127) +#endif + #include #include #include "core/membuf.h" @@ -15,9 +20,14 @@ #define DATA_MOVER_THREADS_DEFAULT_NTHREADS 12 #define DATA_MOVER_THREADS_DEFAULT_RINGBUF_SIZE 128 +struct data_mover_threads_op_fns { + memcpy_fn op_memcpy; +}; + struct data_mover_threads { struct vdm base; /* must be first */ + struct data_mover_threads_op_fns op_fns; struct ringbuf *buf; size_t nthreads; os_thread_t *threads; @@ -33,22 +43,41 @@ struct data_mover_threads_op { uint64_t started; }; +/* + * Standard implementation of memcpy used if none was specified by the user. + */ +void *std_memcpy(void *dst, const void *src, size_t n, unsigned flags) { + return memcpy(dst, src, n); +} + +static struct data_mover_threads_op_fns op_fns_default = { + .op_memcpy = std_memcpy +}; + +void data_mover_threads_set_memcpy_fn(struct data_mover_threads *dmt, + memcpy_fn op_memcpy) { + dmt->op_fns.op_memcpy = op_memcpy; +} + /* * data_mover_threads_do_operation -- implementation of the various * operations supported by this data mover */ static void -data_mover_threads_do_operation(struct data_mover_threads_op *op) +data_mover_threads_do_operation(struct data_mover_threads_op *op, + struct data_mover_threads *dmt) { switch (op->op.type) { case VDM_OPERATION_MEMCPY: { struct vdm_operation_data_memcpy *mdata - = &op->op.memcpy; - memcpy(mdata->dest, mdata->src, mdata->n); + = &op->op.data.memcpy; + memcpy_fn op_memcpy = dmt->op_fns.op_memcpy; + op_memcpy(mdata->dest, + mdata->src, mdata->n, (unsigned)mdata->flags); } break; default: - ASSERT(0); /* unreachable */ - break; + ASSERT(0); /* unreachable */ + break; } if (op->desired_notifier == FUTURE_NOTIFIER_WAKER) { @@ -77,7 +106,7 @@ data_mover_threads_loop(void *arg) if ((op = ringbuf_dequeue(buf)) == NULL) return NULL; - data_mover_threads_do_operation(op); + data_mover_threads_do_operation(op, dmt_threads); } } @@ -104,34 +133,6 @@ data_mover_threads_operation_check(void *op) return FUTURE_STATE_IDLE; } -/* - * data_mover_threads_membuf_check -- checks the status of a threads job - */ -static enum membuf_check_result -data_mover_threads_membuf_check(void *ptr, void *data) -{ - switch (data_mover_threads_operation_check(ptr)) { - case FUTURE_STATE_COMPLETE: - return MEMBUF_PTR_CAN_REUSE; - case FUTURE_STATE_RUNNING: - return MEMBUF_PTR_CAN_WAIT; - case FUTURE_STATE_IDLE: - return MEMBUF_PTR_IN_USE; - } - - ASSERT(0); - return MEMBUF_PTR_IN_USE; -} - -/* - * data_mover_threads_membuf_size -- returns the size of a threads job size - */ -static size_t -data_mover_threads_membuf_size(void *ptr, void *data) -{ - return sizeof(struct data_mover_threads_op); -} - /* * data_mover_threads_operation_new -- create a new thread operation that uses * wakers @@ -169,11 +170,14 @@ data_mover_threads_operation_delete(void *op, switch (opt->op.type) { case VDM_OPERATION_MEMCPY: output->type = VDM_OPERATION_MEMCPY; - output->memcpy.dest = opt->op.memcpy.dest; + output->output.memcpy.dest = + opt->op.data.memcpy.dest; break; default: ASSERT(0); } + + membuf_free(op); } /* @@ -226,13 +230,13 @@ data_mover_threads_new(size_t nthreads, size_t ringbuf_size, dmt_threads->desired_notifier = desired_notifier; dmt_threads->base = data_mover_threads_vdm; + dmt_threads->op_fns = op_fns_default; - dmt_threads->buf = ringbuf_new(ringbuf_size); + dmt_threads->buf = ringbuf_new((unsigned)ringbuf_size); if (dmt_threads->buf == NULL) goto ringbuf_failed; - dmt_threads->membuf = membuf_new(data_mover_threads_membuf_check, - data_mover_threads_membuf_size, NULL, dmt_threads); + dmt_threads->membuf = membuf_new(dmt_threads); if (dmt_threads->membuf == NULL) goto membuf_failed; diff --git a/src/include/libminiasync/data_mover_threads.h b/src/include/libminiasync/data_mover_threads.h index 010911ef4c3..d86d89a8d19 100644 --- a/src/include/libminiasync/data_mover_threads.h +++ b/src/include/libminiasync/data_mover_threads.h @@ -10,15 +10,17 @@ extern "C" { #endif -struct data_mover_threads; +typedef void *(*memcpy_fn)(void *dst, const void *src, + size_t n, unsigned flags); +struct data_mover_threads; struct data_mover_threads *data_mover_threads_new(size_t nthreads, size_t ringbuf_size, enum future_notifier_type desired_notifier); struct data_mover_threads *data_mover_threads_default(); - struct vdm *data_mover_threads_get_vdm(struct data_mover_threads *dmt); - void data_mover_threads_delete(struct data_mover_threads *dmt); +void data_mover_threads_set_memcpy_fn(struct data_mover_threads *dmt, + memcpy_fn op_memcpy); #ifdef __cplusplus } diff --git a/src/include/libminiasync/future.h b/src/include/libminiasync/future.h index fd9c951f3f6..8a13a26d177 100644 --- a/src/include/libminiasync/future.h +++ b/src/include/libminiasync/future.h @@ -153,6 +153,8 @@ do {\ #define FUTURE_AS_RUNNABLE(futurep) (&(futurep)->base) #define FUTURE_OUTPUT(futurep) (&(futurep)->output) +#define FUTURE_DATA(futurep) (&(futurep)->data) +#define FUTURE_STATE(futurep) ((futurep)->base.context.state) typedef void (*future_map_fn)(struct future_context *lhs, struct future_context *rhs, void *arg); @@ -185,7 +187,11 @@ do {\ static inline enum future_state future_poll(struct future *fut, struct future_notifier *notifier) { - return (fut->context.state = fut->task(&fut->context, notifier)); + if (fut->context.state != FUTURE_STATE_COMPLETE) { + fut->context.state = fut->task(&fut->context, notifier); + } + + return fut->context.state; } #define FUTURE_BUSY_POLL(_futurep)\ @@ -195,6 +201,10 @@ while (future_poll(FUTURE_AS_RUNNABLE((_futurep)), NULL) !=\ static inline enum future_state async_chain_impl(struct future_context *ctx, struct future_notifier *notifier) { +#define _MINIASYNC_PTRSIZE sizeof(void *) +#define _MINIASYNC_ALIGN_UP(size)\ + (((size) + _MINIASYNC_PTRSIZE - 1) & ~(_MINIASYNC_PTRSIZE - 1)) + uint8_t *data = future_context_get_data(ctx); struct future_chain_entry *entry = (struct future_chain_entry *)(data); @@ -206,8 +216,14 @@ async_chain_impl(struct future_context *ctx, struct future_notifier *notifier) * Futures must be laid out sequentially in memory for this to work. */ while (entry != NULL) { - used_data += sizeof(struct future_chain_entry) + - future_context_get_size(&entry->future.context); + /* + * `struct future` starts with a pointer, so the structure will + * be pointer-size aligned. We need to account for that when + * calculating where is the next future in a chained struct. + */ + used_data += _MINIASYNC_ALIGN_UP( + sizeof(struct future_chain_entry) + + future_context_get_size(&entry->future.context)); struct future_chain_entry *next = used_data != ctx->data_size ? (struct future_chain_entry *)(data + used_data) : NULL; @@ -227,6 +243,8 @@ async_chain_impl(struct future_context *ctx, struct future_notifier *notifier) } entry = next; } +#undef _MINIASYNC_PTRSIZE +#undef _MINIASYNC_ALIGN_UP return FUTURE_STATE_COMPLETE; } diff --git a/src/include/libminiasync/vdm.h b/src/include/libminiasync/vdm.h index 973140b4d2b..da60bca16bd 100644 --- a/src/include/libminiasync/vdm.h +++ b/src/include/libminiasync/vdm.h @@ -45,7 +45,7 @@ struct vdm_operation { enum vdm_operation_type type; union { struct vdm_operation_data_memcpy memcpy; - }; + } data; }; struct vdm_operation_data { @@ -61,7 +61,7 @@ struct vdm_operation_output { enum vdm_operation_type type; /* XXX: determine if needed */ union { struct vdm_operation_output_memcpy memcpy; - }; + } output; }; FUTURE(vdm_operation_future, @@ -124,10 +124,10 @@ vdm_memcpy(struct vdm *vdm, void *dest, void *src, size_t n, uint64_t flags) { struct vdm_operation op; op.type = VDM_OPERATION_MEMCPY; - op.memcpy.dest = dest; - op.memcpy.flags = flags; - op.memcpy.n = n; - op.memcpy.src = src; + op.data.memcpy.dest = dest; + op.data.memcpy.flags = flags; + op.data.memcpy.n = n; + op.data.memcpy.src = src; struct vdm_operation_future future = {0}; future.data.op = vdm->op_new(vdm, &op); diff --git a/src/windows/include/platform.h b/src/windows/include/platform.h index 2a917c3576d..5754ea41070 100644 --- a/src/windows/include/platform.h +++ b/src/windows/include/platform.h @@ -114,7 +114,6 @@ extern "C" { typedef int mode_t; -#define fchmod(fd, mode) 0 /* XXX - dummy */ #define setlinebuf(fp) setvbuf(fp, NULL, _IOLBF, BUFSIZ); /* unistd.h */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 99a8dbbd6bc..470615642d9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,7 +11,7 @@ set(LIBS_BASIC ${CMAKE_THREAD_LIBS_INIT}) set(LIBS_DML - miniasync-dml + miniasync-vdm-dml dl dml ${LIBS_BASIC}) @@ -22,8 +22,11 @@ set(SOURCES_DUMMY_TEST set(SOURCES_DUMMY_NEGATIVE_TEST dummy_negative/dummy_negative.c) +set(SOURCES_FUTURE_TEST + future/test_future.c) + set(SOURCES_MEMCPY_PTHREADS_TEST - memcpy_threads/memcpy_threads.c) + memcpy_threads/memcpy_threads.c) set(SOURCES_DATA_MOVER_DML_TEST data_mover_dml/data_mover_dml.c @@ -58,6 +61,10 @@ add_link_executable(dummy_negative "${SOURCES_DUMMY_NEGATIVE_TEST}" "${LIBS_BASIC}") +add_link_executable(future + "${SOURCES_FUTURE_TEST}" + "${LIBS_BASIC}") + add_link_executable(memcpy_threads "${SOURCES_MEMCPY_PTHREADS_TEST}" "${LIBS_BASIC}") @@ -72,12 +79,18 @@ test("dummy_drd" "dummy" test_dummy drd) test("dummy_helgrind" "dummy" test_dummy helgrind) test("dummy_memcheck" "dummy" test_dummy memcheck) test("dummy_negative" "dummy_negative" test_dummy_negative none) -test("ex_basic" "ex_basic" test_ex_basic none) -test("ex_basic_async" "ex_basic_async" test_ex_basic_async none) +test("future" "future" test_future none) +test("future_memcheck" "future" test_future memcheck) test("memcpy_threads" "memcpy_threads" test_memcpy_threads none) test("membuf" "membuf" test_membuf none) -# add miniasync-dml test only if the sources in extras/dml were compiled +# add tests running examples only if they are built +if(BUILD_EXAMPLES) + test("ex_basic" "ex_basic" test_ex_basic none) + test("ex_basic_async" "ex_basic_async" test_ex_basic_async none) +endif() + +# add miniasync-vdm-dml test only if the sources in extras/dml were compiled if (COMPILE_DML) add_link_executable(data_mover_dml "${SOURCES_DATA_MOVER_DML_TEST}" diff --git a/tests/data_mover_dml/data_mover_dml.c b/tests/data_mover_dml/data_mover_dml.c index 0c503a61e5e..4b3061e3044 100644 --- a/tests/data_mover_dml/data_mover_dml.c +++ b/tests/data_mover_dml/data_mover_dml.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include "util_dml.h" diff --git a/tests/future/test_future.c b/tests/future/test_future.c new file mode 100644 index 00000000000..937f3bb3544 --- /dev/null +++ b/tests/future/test_future.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2022, Intel Corporation */ + +#include "libminiasync/future.h" +#include "test_helpers.h" +#include +#include +#include +#include + +#define TEST_MAX_COUNT 10 +#define FAKE_NOTIFIER ((void *)((uintptr_t)(0xDEADBEEF))) +#define FAKE_MAP_ARG ((void *)((uintptr_t)(0xFEEDCAFE))) + +struct countup_data { + int counter; + int max_count; +}; + +struct countup_output { + int result; +}; + +FUTURE(countup_fut, struct countup_data, struct countup_output); + +enum future_state +countup_task(struct future_context *context, + struct future_notifier *notifier) +{ + UT_ASSERTeq(notifier, FAKE_NOTIFIER); + + struct countup_data *data = future_context_get_data(context); + data->counter++; + if (data->counter == data->max_count) { + struct countup_output *output = + future_context_get_output(context); + output->result += 1; + return FUTURE_STATE_COMPLETE; + } else { + return FUTURE_STATE_RUNNING; + } +} + +struct countup_fut +async_countup(int max_count) +{ + struct countup_fut fut = {0}; + FUTURE_INIT(&fut, countup_task); + fut.data.counter = 0; + fut.data.max_count = max_count; + fut.output.result = 0; + + return fut; +} + +void +test_single_future(void) +{ + struct countup_fut up = async_countup(TEST_MAX_COUNT); + UT_ASSERTeq(FUTURE_STATE(&up), FUTURE_STATE_IDLE); + + struct countup_output *output = FUTURE_OUTPUT(&up); + UT_ASSERTeq(output->result, 0); + + struct countup_data *data = FUTURE_DATA(&up); + UT_ASSERTeq(data->counter, 0); + + enum future_state state = FUTURE_STATE_RUNNING; + + for (int i = 0; i < TEST_MAX_COUNT; ++i) { + UT_ASSERTeq(state, FUTURE_STATE_RUNNING); + UT_ASSERTeq(FUTURE_STATE(&up), i == 0 ? + FUTURE_STATE_IDLE : FUTURE_STATE_RUNNING); + UT_ASSERTeq(data->counter, i); + UT_ASSERTeq(output->result, 0); + + state = future_poll(FUTURE_AS_RUNNABLE(&up), FAKE_NOTIFIER); + } + UT_ASSERTeq(data->counter, TEST_MAX_COUNT); + UT_ASSERTeq(output->result, 1); + UT_ASSERTeq(state, FUTURE_STATE_COMPLETE); + + /* polling on a complete future is a noop */ + state = future_poll(FUTURE_AS_RUNNABLE(&up), FAKE_NOTIFIER); + + UT_ASSERTeq(data->counter, TEST_MAX_COUNT); + UT_ASSERTeq(output->result, 1); + UT_ASSERTeq(state, FUTURE_STATE_COMPLETE); +} + +struct countdown_data { + int counter; +}; + +struct countdown_output { + int result; +}; + +FUTURE(countdown_fut, struct countdown_data, struct countdown_output); + +enum future_state +countdown_task(struct future_context *context, + struct future_notifier *notifier) +{ + UT_ASSERTeq(notifier, FAKE_NOTIFIER); + + struct countdown_data *data = future_context_get_data(context); + data->counter--; + if (data->counter == 0) { + struct countdown_output *output = + future_context_get_output(context); + output->result += 1; + return FUTURE_STATE_COMPLETE; + } else { + return FUTURE_STATE_RUNNING; + } +} + +struct countdown_fut +async_countdown(int count) +{ + struct countdown_fut fut = {0}; + FUTURE_INIT(&fut, countdown_task); + fut.data.counter = count; + fut.output.result = 0; + + return fut; +} + +struct up_down_data { + FUTURE_CHAIN_ENTRY(struct countup_fut, up); + FUTURE_CHAIN_ENTRY(struct countdown_fut, down); +}; + +struct up_down_output { + int result_sum; +}; + +FUTURE(up_down_fut, struct up_down_data, struct up_down_output); + +void +up_to_down_map(struct future_context *lhs, struct future_context *rhs, + void *arg) +{ + UT_ASSERTeq(arg, FAKE_MAP_ARG); + + struct countup_data *up_data = future_context_get_data(lhs); + struct countup_output *up_output = future_context_get_output(lhs); + struct countdown_data *down_data = future_context_get_data(rhs); + struct countdown_output *down_output = future_context_get_output(rhs); + + down_data->counter = up_data->counter; + down_output->result += up_output->result; +} + +void +down_to_result_map(struct future_context *lhs, struct future_context *rhs, + void *arg) +{ + UT_ASSERTeq(arg, FAKE_MAP_ARG); + struct countdown_data *down_data = future_context_get_data(lhs); + UT_ASSERTeq(down_data->counter, 0); + + struct countdown_output *down_output = future_context_get_output(lhs); + struct up_down_output *output = future_context_get_output(rhs); + output->result_sum = down_output->result; +} + +struct up_down_fut +async_up_down(int count) +{ + struct up_down_fut fut = {0}; + FUTURE_CHAIN_ENTRY_INIT(&fut.data.up, async_countup(count), + up_to_down_map, FAKE_MAP_ARG); + FUTURE_CHAIN_ENTRY_INIT(&fut.data.down, async_countdown(0), + down_to_result_map, FAKE_MAP_ARG); + FUTURE_CHAIN_INIT(&fut); + + return fut; +} + +void +test_chained_future() +{ + struct up_down_fut fut = async_up_down(TEST_MAX_COUNT); + UT_ASSERTeq(FUTURE_STATE(&fut), FUTURE_STATE_IDLE); + + for (int i = 0; i < TEST_MAX_COUNT * 2; ++i) { + future_poll(FUTURE_AS_RUNNABLE(&fut), FAKE_NOTIFIER); + } + + UT_ASSERTeq(FUTURE_STATE(&fut), FUTURE_STATE_COMPLETE); + + struct up_down_output *output = FUTURE_OUTPUT(&fut); + UT_ASSERTeq(output->result_sum, 2); +} + +int +main(void) +{ + test_single_future(); + test_chained_future(); + + return 0; +} diff --git a/tests/future/test_future.cmake b/tests/future/test_future.cmake new file mode 100644 index 00000000000..632f9906586 --- /dev/null +++ b/tests/future/test_future.cmake @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2022, Intel Corporation + +# an example for the basic test case + +include(${SRC_DIR}/cmake/test_helpers.cmake) + +setup() + +# The expected input can be provided to the execute function, +# which will check if the return code of the binary file matches. +execute(0 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${BUILD}/future) + +# execute_assert_pass can be used instead of manually checking if +# the return code equals zero, however it cannot be used with a tracer. +# When used with a tracer assert_pass will be skipped. +execute_assert_pass(${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${BUILD}/future) + +cleanup() diff --git a/tests/membuf/membuf_simple.c b/tests/membuf/membuf_simple.c index d8cded7e4df..8bf05386602 100644 --- a/tests/membuf/membuf_simple.c +++ b/tests/membuf/membuf_simple.c @@ -3,105 +3,73 @@ #include #include -#include #include "core/membuf.h" +#include "test_helpers.h" -#define TEST_FUNC_DATA (void *)(0xDEADBEEF) -#define TEST_USER_DATA (void *)(0xC0FFEA) +#define TEST_USER_DATA (void *)(0xC0FFEE) #define TEST_ENTRY_PADDING (1 << 11) #define MAX_TEST_ENTRIES (100000) struct test_entry { - enum membuf_check_result check; - size_t size; char padding[TEST_ENTRY_PADDING]; }; -static enum membuf_check_result -test_check(void *ptr, void *data) -{ - assert(data == TEST_FUNC_DATA); - - struct test_entry *entry = ptr; - return entry->check; -} - -static size_t -test_size(void *ptr, void *data) -{ - assert(data == TEST_FUNC_DATA); - - struct test_entry *entry = ptr; - return entry->size; -} - -static struct test_entry * -test_entry_new(struct membuf *mbuf, enum membuf_check_result check) -{ - struct test_entry *entry = - membuf_alloc(mbuf, sizeof(struct test_entry)); - if (entry == NULL) - return NULL; - entry->check = check; - entry->size = sizeof(struct test_entry); - - return entry; -} - int main(int argc, char *argv[]) { - struct membuf *mbuf = membuf_new(test_check, test_size, TEST_FUNC_DATA, - TEST_USER_DATA); + struct membuf *mbuf = membuf_new(TEST_USER_DATA); struct test_entry **entries = malloc(sizeof(struct test_entry *) * MAX_TEST_ENTRIES); - assert(entries != NULL); + UT_ASSERTne(entries, NULL); int i; for (i = 0; i < MAX_TEST_ENTRIES; ++i) { struct test_entry *entry = - test_entry_new(mbuf, MEMBUF_PTR_IN_USE); + membuf_alloc(mbuf, sizeof(struct test_entry)); if (entry == NULL) break; - assert(membuf_ptr_user_data(entry) == TEST_USER_DATA); + UT_ASSERTeq(membuf_ptr_user_data(entry), TEST_USER_DATA); entries[i] = entry; } /* if this triggers, increase MAX_TEST_ENTRIES */ - assert(i != MAX_TEST_ENTRIES); + UT_ASSERTne(i, MAX_TEST_ENTRIES); int entries_max = i; for (i = 0; i < entries_max / 2; ++i) { struct test_entry *entry = entries[i]; - entry->check = MEMBUF_PTR_CAN_REUSE; + membuf_free(entry); } + int allocated = 0; for (i = 0; i < MAX_TEST_ENTRIES; ++i) { struct test_entry *entry = - test_entry_new(mbuf, MEMBUF_PTR_IN_USE); + membuf_alloc(mbuf, sizeof(struct test_entry)); if (entry == NULL) break; - assert(membuf_ptr_user_data(entry) == TEST_USER_DATA); + UT_ASSERTeq(membuf_ptr_user_data(entry), TEST_USER_DATA); } - assert(i == entries_max / 2); + allocated += i; + UT_ASSERTeq(i, entries_max / 2); for (i = entries_max / 2; i < entries_max; ++i) { struct test_entry *entry = entries[i]; - entry->check = MEMBUF_PTR_CAN_REUSE; + membuf_free(entry); } for (i = 0; i < MAX_TEST_ENTRIES; ++i) { struct test_entry *entry = - test_entry_new(mbuf, MEMBUF_PTR_IN_USE); + membuf_alloc(mbuf, sizeof(struct test_entry)); if (entry == NULL) break; - assert(membuf_ptr_user_data(entry) == TEST_USER_DATA); + UT_ASSERTeq(membuf_ptr_user_data(entry), TEST_USER_DATA); } - assert(i == entries_max / 2); + allocated += i; + UT_ASSERTeq(allocated, entries_max); membuf_delete(mbuf); free(entries); diff --git a/tests/test_helpers.h b/tests/test_helpers.h index 8858d250291..7a2682967a1 100644 --- a/tests/test_helpers.h +++ b/tests/test_helpers.h @@ -34,6 +34,11 @@ (unsigned long long)(x), (unsigned long long)(y));\ } while (/*CONSTCOND*/0) +#define UT_ASSERTne(x, y) do if ((x) == (y)) {\ + UT_FATAL("ASSERT FAILED : " #x " (%llu) = %llu",\ + (unsigned long long)(x), (unsigned long long)(y));\ +} while (/*CONSTCOND*/0) + #define UT_ASSERTin(x, min, max) do if ((x) < (min) || (x) > (max)) {\ UT_FATAL("ASSERT FAILED : " #x " = %llu not in [%llu,%llu]",\ (unsigned long long)(x),\ diff --git a/utils/docker/images/Dockerfile.fedora-35 b/utils/docker/images/Dockerfile.fedora-35 index 1a0c7f42fd5..688c350a60c 100644 --- a/utils/docker/images/Dockerfile.fedora-35 +++ b/utils/docker/images/Dockerfile.fedora-35 @@ -50,7 +50,7 @@ ENV MINIASYNC_DEPS "\ graphviz \ pandoc " -# MINIASYNC-DML deps +# MINIASYNC-VDM-DML deps ENV MINIASYNC_DML_DEPS "\ libuuid-devel" diff --git a/utils/docker/images/Dockerfile.ubuntu-21.04 b/utils/docker/images/Dockerfile.ubuntu-21.04 index d5cabf124c4..06e1390709c 100644 --- a/utils/docker/images/Dockerfile.ubuntu-21.04 +++ b/utils/docker/images/Dockerfile.ubuntu-21.04 @@ -65,7 +65,7 @@ ENV MINIASYNC_DEPS "\ graphviz \ pandoc" -# MINIASYNC-DML deps +# MINIASYNC-VDM-DML deps ENV MINIASYNC_DML_DEPS "\ uuid-dev"