Share futex between unrelated processes
Asked Answered
F

2

7

How can unrelated processes cooperate using a futex?

Let's say I have unrelated processes, one being, say, an apache subprocess with my module, another being e.g. a background script.

I'd like to establish a condition variable with a mutex between the two using a futex, to benefit for user-space fast code path.

It seems to me that memory at which mutex is stored could be in a mmap'd file, if that memory is mapped, e.g. mlock'd the two processes could theoretically issue futex calls against same address.

Alternatively, perhaps a futex can be passed from one process to another using FUTEX_FD.

Code submissions low-, high-level and dynamic languages are accepted (C, C++, Python, etc.). "robust futex" API must be supported too.

References:

Frail answered 8/2, 2016 at 9:7 Comment(6)
P.S. If this cannot be done, please explain in detail why.Frail
The manpage says that pthreads uses futexes internally. Did you consider to simply use the high level API (as the futex manpage recommends), and use a pthread condition with PTHREAD_PROCESS_SHARED?Epithelioma
have you checked this locklessinc.com/articles/mutex_cv_futexExcitation
@Excitation yes I did, it's listed in the question.Frail
@Epithelioma looks like linux.die.net/man/3/pthread_mutexattr_init has an example code that in fact sets up a futex in a mmaped without common fork parent. Good hint!Frail
From man7.org/linux/man-pages/man2/futex.2.html In order to share a futex between processes, the futex is placed in a region of shared memory, created using (for example) mmap(2) or shmat(2). Should not be difficult to implement.Rendition
F
0

Thanks Phillip and Felix M. for pointers.

Python user code (file with data structures already exists, initialised with PTHREAD_PROCESS_SHARED)

with open("/tmp/semaphore", "rb+") as f:
    m = mmap.mmap(f.fileno(), 0)  # default: all file, share, read-write

data = ffi.cast("unsigned long[3]", id(m))[2]  # pointer to mapped area, 64-bit CPython
lock = ffi.cast("pthread_mutex_t *", data)
cond = ffi.cast("pthread_cond_t *", data + 40)

@contextlib.contextmanager
def locked(alock):
    assert not C.pthread_mutex_lock(alock)
    try:
        yield
    finally:
        assert not C.pthread_mutex_unlock(alock)

Wait and get awoken:

if "wait" in sys.argv:
    with locked(lock):
        assert not C.pthread_cond_wait(cond, lock)

elif "signal" in sys.argv:
    with locked(lock):
        assert not C.pthread_cond_signal(cond)

Basics of setting PTHREAD_PROCESS_SHARED:

l = ffi.new("pthread_mutexattr_t *")
assert not C.pthread_mutexattr_init(l)
assert not C.pthread_mutexattr_setpshared(l, 1)  # PTHREAD_PROCESS_SHARED
assert not C.pthread_mutex_init(lock, l)
# same for condition variable

Full code for nitpicks :-) https://github.com/dimaqq/pthread_mutexattr_init/blob/master/xsem.py based on http://linux.die.net/man/3/pthread_mutexattr_init

Frail answered 19/2, 2016 at 17:57 Comment(0)
E
0

mutex are defined to lock access to shared resources. This does not seem what you want to do .

if you want both process to cooperate, you may either use shared mmap area, or semaphore

Exemplary answered 18/2, 2016 at 14:59 Comment(1)
note futex in the OP. Also note comments by Felix and PhillipFrail
F
0

Thanks Phillip and Felix M. for pointers.

Python user code (file with data structures already exists, initialised with PTHREAD_PROCESS_SHARED)

with open("/tmp/semaphore", "rb+") as f:
    m = mmap.mmap(f.fileno(), 0)  # default: all file, share, read-write

data = ffi.cast("unsigned long[3]", id(m))[2]  # pointer to mapped area, 64-bit CPython
lock = ffi.cast("pthread_mutex_t *", data)
cond = ffi.cast("pthread_cond_t *", data + 40)

@contextlib.contextmanager
def locked(alock):
    assert not C.pthread_mutex_lock(alock)
    try:
        yield
    finally:
        assert not C.pthread_mutex_unlock(alock)

Wait and get awoken:

if "wait" in sys.argv:
    with locked(lock):
        assert not C.pthread_cond_wait(cond, lock)

elif "signal" in sys.argv:
    with locked(lock):
        assert not C.pthread_cond_signal(cond)

Basics of setting PTHREAD_PROCESS_SHARED:

l = ffi.new("pthread_mutexattr_t *")
assert not C.pthread_mutexattr_init(l)
assert not C.pthread_mutexattr_setpshared(l, 1)  # PTHREAD_PROCESS_SHARED
assert not C.pthread_mutex_init(lock, l)
# same for condition variable

Full code for nitpicks :-) https://github.com/dimaqq/pthread_mutexattr_init/blob/master/xsem.py based on http://linux.die.net/man/3/pthread_mutexattr_init

Frail answered 19/2, 2016 at 17:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.