Skip to content

Use shared memory + spinlock & semaphore to perform IPC message passing in preload mode.#924

Merged
rwails merged 17 commits intoshadow:devfrom
rwails:spinlock
Aug 26, 2020
Merged

Use shared memory + spinlock & semaphore to perform IPC message passing in preload mode.#924
rwails merged 17 commits intoshadow:devfrom
rwails:spinlock

Conversation

@rwails
Copy link
Copy Markdown
Collaborator

@rwails rwails commented Aug 13, 2020

No description provided.

Ryan Wails and others added 11 commits July 16, 2020 23:28
plugin both implement the following IPC communication pattern:

plugin:
        recv -> send -> recv -> send ...

shadow:
        send -> recv -> send -> recv ...

This commit patches a case where shared memory communication would
sometimes cause the pattern:

shadow:
        ... send -> send -> recv ...

and vice-versa on the plugin.

This commit also implements a more sophisticated spin lock/semaphore in
the gate CPP module.
@codecov
Copy link
Copy Markdown

codecov bot commented Aug 13, 2020

Codecov Report

Merging #924 into dev will decrease coverage by 0.02%.
The diff coverage is 20.52%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev     #924      +/-   ##
==========================================
- Coverage   55.74%   55.72%   -0.03%     
==========================================
  Files         135      137       +2     
  Lines       20957    21015      +58     
  Branches     4833     4837       +4     
==========================================
+ Hits        11683    11710      +27     
- Misses       6106     6130      +24     
- Partials     3168     3175       +7     
Flag Coverage Δ
#tests 55.72% <20.52%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/main/host/thread_preload.c 0.00% <0.00%> (ø)
src/main/shmem/shmem_allocator.h 0.00% <ø> (ø)
src/shim/binary_spinning_sem.cc 0.00% <0.00%> (ø)
src/shim/binary_spinning_sem.h 0.00% <0.00%> (ø)
src/shim/ipc.cc 0.00% <0.00%> (ø)
src/shim/preload_syscalls.c 21.00% <0.00%> (-0.11%) ⬇️
src/shim/shim.c 25.64% <0.00%> (-1.03%) ⬇️
src/shim/shim_shmem.c 0.00% <0.00%> (ø)
src/main/shmem/shmem_test.c 80.20% <77.77%> (-0.23%) ⬇️
src/main/shmem/shmem_allocator.c 70.83% <83.33%> (+0.83%) ⬆️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 523eebc...62fba80. Read the comment docs.

SysCallHandler* sys;

int eventFD;
pid_t childPID;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The base Thread struct now has this

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

};

shimevent_sendEvent(thread->eventFD, &ipc_complete_ev);
ShimEvent resp = {0};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - move to after next statement, just before first use?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

# -D_GNU_SOURCE enables some additional features in libc, such at RTLD_NEXT.
target_compile_options(${SHIM_HELPER_LIB} PRIVATE -D_GNU_SOURCE)
target_compile_options(${SHIM_HELPER_LIB} PRIVATE -D_GNU_SOURCE -fPIC)
target_link_libraries(${SHIM_HELPER_LIB} PRIVATE shadow-shmem)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be INTERFACE? I don't think PRIVATE makes sense for a static library target, since its dependencies won't actually be linked into the library; its dependencies need to be included by the binary target(s) that use the library.

From https://cmake.org/cmake/help/v3.0/command/target_link_libraries.html?highlight=target_link_libraries :

The PUBLIC, PRIVATE and INTERFACE keywords can be used to specify both the link dependencies and the link interface in one command. Libraries and targets following PUBLIC are linked to, and are made part of the link interface. Libraries and targets following PRIVATE are linked to, but are not made part of the link interface. Libraries following INTERFACE are appended to the link interface and are not used for linking .

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to interface.

src/shim/gate.cc Outdated
#define SHD_GATE_SPIN_MAX 8096

void gate_init(Gate *gate) {
std::memset(gate, 0, sizeof(Gate));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC memset'ing an object to zero is a bit of a gray area for type safety in the standard. It's probably fine in practice, but better to either use struct initialization to default-init the struct in a type-aware way (*gate = {0}), and/or explicitly init all members (gate->x is currently not initialized other than in this memset).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. n.b. C++ doesn't support the lovely = {0} syntax to zero all struct members.

src/shim/gate.h Outdated
pthread_spinlock_t lock;
};

void gate_init(Gate *gate);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling a little bit with the "gate" metaphor. Could perhaps use a brief explanation (and/or a reference if it's a standard term, though I didn't have much luck searching)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to BinarySpinningSem

@rwails rwails requested a review from sporksmith August 19, 2020 21:39
}

#ifndef NDEBUG
static void _print(void* pool, size_t pool_nbytes, void* meta) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe keep around in case you want it again for debugging? You could just #if 0 it out to avoid dead code warnings.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think let's leave it out. The block is pretty old and probably only makes sense to me. I can dig it out of the history if needed.

src/shim/ipc.cc Outdated
extern "C" {

void ipcData_init(IPCData *ipc_data) {
memset(ipc_data, 0, sizeof(IPCData));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As before, memset is a bit fragile here. Now I remember that this is especially the case for a C++ object, since a memset won't run the constructors of any member objects, if applicable.

As far as I can tell struct init does technically work here, but actually is also fragile due to c++ destuctors: if IPCData or any of its members have destructors, they'd run on the garbage data at ipc_data before calling IPCData's constructor (you haven't defined one, but IIRC there's implicitly one that default-initializes all members).

I think the idiomatic, safe way to do this is to replace IPCData::init with a constructor IPDCata::IPCData, and here use a placement new.

Demo: https://godbolt.org/z/df9Gjc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could add a static assertion that IPCData (and therefore its members) doesn't have any nontrivial constructor or destructors, in which case the struct-init, or even the memset, should be safe: https://godbolt.org/z/c6nsTa

    void ipcData_init(IPCData *ipc_data) {
        static_assert(std::is_trivial<IPCData>());
        static_assert(std::is_trivially_destructible<IPCData>());
        *ipc_data = {};
    }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I think memsetting a class has bitten me before. I had heard of placement new, but had forgotten its use since. Fixed!

Copy link
Copy Markdown
Contributor

@sporksmith sporksmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! The coverage test is currently broken, so you can ignore that failure. @stevenengler is about to disable it.

You should be able to fix the bindings-lint check by running cd build; make bindings. (You may need to install bindgen and cbindgen first if you haven't already)

@sporksmith
Copy link
Copy Markdown
Contributor

You should be able to fix the bindings-lint check by running cd build; make bindings. (You may need to install bindgen and cbindgen first if you haven't already)

Actually the binding failure is spurious too; will be fixed by #940

@stevenengler
Copy link
Copy Markdown
Contributor

All of the CI issues should be resolved now.

@rwails rwails merged commit 6fba546 into shadow:dev Aug 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants