Cygwin: FIFO: add shared memory
Even though we currently allow a FIFO to be opened for reading only once, we can still have more than one reader open because of dup and fork. Add a named shared memory section accessible to all readers of a given FIFO. In future commits we will add information needed by all readers to this section Add a class fifo_shmem_t that lets us access this information. Add a method create_shmem that is called when a reader opens, and add a method reopen_shmem that is called by dup, fork, and exec. (Each new reader needs its own view of the shared memory.)
This commit is contained in:
parent
71726ba70b
commit
878eb22462
@ -1300,6 +1300,11 @@ struct fifo_client_handler
|
|||||||
int pipe_state ();
|
int pipe_state ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Info needed by all readers of a FIFO, stored in named shared memory. */
|
||||||
|
class fifo_shmem_t
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
class fhandler_fifo: public fhandler_base
|
class fhandler_fifo: public fhandler_base
|
||||||
{
|
{
|
||||||
/* Handles to named events shared by all fhandlers for a given FIFO. */
|
/* Handles to named events shared by all fhandlers for a given FIFO. */
|
||||||
@ -1319,6 +1324,10 @@ class fhandler_fifo: public fhandler_base
|
|||||||
af_unix_spinlock_t _fifo_client_lock;
|
af_unix_spinlock_t _fifo_client_lock;
|
||||||
bool reader, writer, duplexer;
|
bool reader, writer, duplexer;
|
||||||
size_t max_atomic_write;
|
size_t max_atomic_write;
|
||||||
|
|
||||||
|
HANDLE shmem_handle;
|
||||||
|
fifo_shmem_t *shmem;
|
||||||
|
|
||||||
bool __reg2 wait (HANDLE);
|
bool __reg2 wait (HANDLE);
|
||||||
static NTSTATUS npfs_handle (HANDLE &);
|
static NTSTATUS npfs_handle (HANDLE &);
|
||||||
HANDLE create_pipe_instance (bool);
|
HANDLE create_pipe_instance (bool);
|
||||||
@ -1330,6 +1339,9 @@ class fhandler_fifo: public fhandler_base
|
|||||||
void record_connection (fifo_client_handler&,
|
void record_connection (fifo_client_handler&,
|
||||||
fifo_client_connect_state = fc_connected);
|
fifo_client_connect_state = fc_connected);
|
||||||
|
|
||||||
|
int create_shmem ();
|
||||||
|
int reopen_shmem ();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
fhandler_fifo ();
|
fhandler_fifo ();
|
||||||
bool hit_eof ();
|
bool hit_eof ();
|
||||||
@ -1341,6 +1353,7 @@ public:
|
|||||||
DWORD fifo_reader_thread_func ();
|
DWORD fifo_reader_thread_func ();
|
||||||
void fifo_client_lock () { _fifo_client_lock.lock (); }
|
void fifo_client_lock () { _fifo_client_lock.lock (); }
|
||||||
void fifo_client_unlock () { _fifo_client_lock.unlock (); }
|
void fifo_client_unlock () { _fifo_client_lock.unlock (); }
|
||||||
|
|
||||||
int open (int, mode_t);
|
int open (int, mode_t);
|
||||||
off_t lseek (off_t offset, int whence);
|
off_t lseek (off_t offset, int whence);
|
||||||
int close ();
|
int close ();
|
||||||
|
@ -70,7 +70,8 @@ fhandler_fifo::fhandler_fifo ():
|
|||||||
read_ready (NULL), write_ready (NULL), writer_opening (NULL),
|
read_ready (NULL), write_ready (NULL), writer_opening (NULL),
|
||||||
cancel_evt (NULL), thr_sync_evt (NULL), _maybe_eof (false), nhandlers (0),
|
cancel_evt (NULL), thr_sync_evt (NULL), _maybe_eof (false), nhandlers (0),
|
||||||
reader (false), writer (false), duplexer (false),
|
reader (false), writer (false), duplexer (false),
|
||||||
max_atomic_write (DEFAULT_PIPEBUFSIZE)
|
max_atomic_write (DEFAULT_PIPEBUFSIZE),
|
||||||
|
shmem_handle (NULL), shmem (NULL)
|
||||||
{
|
{
|
||||||
pipe_name_buf[0] = L'\0';
|
pipe_name_buf[0] = L'\0';
|
||||||
need_fork_fixup (true);
|
need_fork_fixup (true);
|
||||||
@ -441,6 +442,67 @@ canceled:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_fifo::create_shmem ()
|
||||||
|
{
|
||||||
|
HANDLE sect;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
NTSTATUS status;
|
||||||
|
LARGE_INTEGER size = { .QuadPart = sizeof (fifo_shmem_t) };
|
||||||
|
SIZE_T viewsize = sizeof (fifo_shmem_t);
|
||||||
|
PVOID addr = NULL;
|
||||||
|
UNICODE_STRING uname;
|
||||||
|
WCHAR shmem_name[MAX_PATH];
|
||||||
|
|
||||||
|
__small_swprintf (shmem_name, L"fifo-shmem.%08x.%016X", get_dev (),
|
||||||
|
get_ino ());
|
||||||
|
RtlInitUnicodeString (&uname, shmem_name);
|
||||||
|
InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT,
|
||||||
|
get_shared_parent_dir (), NULL);
|
||||||
|
status = NtCreateSection (§, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
|
||||||
|
| SECTION_MAP_READ | SECTION_MAP_WRITE,
|
||||||
|
&attr, &size, PAGE_READWRITE, SEC_COMMIT, NULL);
|
||||||
|
if (status == STATUS_OBJECT_NAME_COLLISION)
|
||||||
|
status = NtOpenSection (§, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
|
||||||
|
| SECTION_MAP_READ | SECTION_MAP_WRITE, &attr);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = NtMapViewOfSection (sect, NtCurrentProcess (), &addr, 0, viewsize,
|
||||||
|
NULL, &viewsize, ViewShare, 0, PAGE_READWRITE);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
NtClose (sect);
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
shmem_handle = sect;
|
||||||
|
shmem = (fifo_shmem_t *) addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shmem_handle must be valid when this is called. */
|
||||||
|
int
|
||||||
|
fhandler_fifo::reopen_shmem ()
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
SIZE_T viewsize = sizeof (fifo_shmem_t);
|
||||||
|
PVOID addr = NULL;
|
||||||
|
|
||||||
|
status = NtMapViewOfSection (shmem_handle, NtCurrentProcess (), &addr,
|
||||||
|
0, viewsize, NULL, &viewsize, ViewShare,
|
||||||
|
0, PAGE_READWRITE);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
shmem = (fifo_shmem_t *) addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_fifo::open (int flags, mode_t)
|
fhandler_fifo::open (int flags, mode_t)
|
||||||
{
|
{
|
||||||
@ -501,12 +563,15 @@ fhandler_fifo::open (int flags, mode_t)
|
|||||||
goto err_close_write_ready;
|
goto err_close_write_ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're reading, signal read_ready and start the fifo_reader_thread. */
|
/* If we're reading, signal read_ready, create the shared memory,
|
||||||
|
and start the fifo_reader_thread. */
|
||||||
if (reader)
|
if (reader)
|
||||||
{
|
{
|
||||||
SetEvent (read_ready);
|
SetEvent (read_ready);
|
||||||
if (!(cancel_evt = create_event ()))
|
if (create_shmem () < 0)
|
||||||
goto err_close_writer_opening;
|
goto err_close_writer_opening;
|
||||||
|
if (!(cancel_evt = create_event ()))
|
||||||
|
goto err_close_shmem;
|
||||||
if (!(thr_sync_evt = create_event ()))
|
if (!(thr_sync_evt = create_event ()))
|
||||||
goto err_close_cancel_evt;
|
goto err_close_cancel_evt;
|
||||||
new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
|
new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
|
||||||
@ -615,6 +680,9 @@ err_close_reader:
|
|||||||
return 0;
|
return 0;
|
||||||
err_close_cancel_evt:
|
err_close_cancel_evt:
|
||||||
NtClose (cancel_evt);
|
NtClose (cancel_evt);
|
||||||
|
err_close_shmem:
|
||||||
|
NtUnmapViewOfSection (NtCurrentProcess (), shmem);
|
||||||
|
NtClose (shmem_handle);
|
||||||
err_close_writer_opening:
|
err_close_writer_opening:
|
||||||
NtClose (writer_opening);
|
NtClose (writer_opening);
|
||||||
err_close_write_ready:
|
err_close_write_ready:
|
||||||
@ -944,6 +1012,10 @@ fhandler_fifo::close ()
|
|||||||
dup/fork/exec; we should only reset read_ready when the last
|
dup/fork/exec; we should only reset read_ready when the last
|
||||||
one closes. */
|
one closes. */
|
||||||
ResetEvent (read_ready);
|
ResetEvent (read_ready);
|
||||||
|
if (shmem)
|
||||||
|
NtUnmapViewOfSection (NtCurrentProcess (), shmem);
|
||||||
|
if (shmem_handle)
|
||||||
|
NtClose (shmem_handle);
|
||||||
}
|
}
|
||||||
if (read_ready)
|
if (read_ready)
|
||||||
NtClose (read_ready);
|
NtClose (read_ready);
|
||||||
@ -1014,6 +1086,15 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
|
|||||||
/* Make sure the child starts unlocked. */
|
/* Make sure the child starts unlocked. */
|
||||||
fhf->fifo_client_unlock ();
|
fhf->fifo_client_unlock ();
|
||||||
|
|
||||||
|
if (!DuplicateHandle (GetCurrentProcess (), shmem_handle,
|
||||||
|
GetCurrentProcess (), &fhf->shmem_handle,
|
||||||
|
0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
|
||||||
|
{
|
||||||
|
__seterrno ();
|
||||||
|
goto err_close_writer_opening;
|
||||||
|
}
|
||||||
|
if (fhf->reopen_shmem () < 0)
|
||||||
|
goto err_close_shmem_handle;
|
||||||
fifo_client_lock ();
|
fifo_client_lock ();
|
||||||
for (i = 0; i < nhandlers; i++)
|
for (i = 0; i < nhandlers; i++)
|
||||||
{
|
{
|
||||||
@ -1044,7 +1125,10 @@ err_close_cancel_evt:
|
|||||||
err_close_handlers:
|
err_close_handlers:
|
||||||
for (int j = 0; j < i; j++)
|
for (int j = 0; j < i; j++)
|
||||||
fhf->fc_handler[j].close ();
|
fhf->fc_handler[j].close ();
|
||||||
/* err_close_writer_opening: */
|
NtUnmapViewOfSection (GetCurrentProcess (), fhf->shmem);
|
||||||
|
err_close_shmem_handle:
|
||||||
|
NtClose (fhf->shmem_handle);
|
||||||
|
err_close_writer_opening:
|
||||||
NtClose (fhf->writer_opening);
|
NtClose (fhf->writer_opening);
|
||||||
err_close_write_ready:
|
err_close_write_ready:
|
||||||
NtClose (fhf->write_ready);
|
NtClose (fhf->write_ready);
|
||||||
@ -1066,6 +1150,9 @@ fhandler_fifo::fixup_after_fork (HANDLE parent)
|
|||||||
/* Make sure the child starts unlocked. */
|
/* Make sure the child starts unlocked. */
|
||||||
fifo_client_unlock ();
|
fifo_client_unlock ();
|
||||||
|
|
||||||
|
fork_fixup (parent, shmem_handle, "shmem_handle");
|
||||||
|
if (reopen_shmem () < 0)
|
||||||
|
api_fatal ("Can't reopen shared memory during fork, %E");
|
||||||
fifo_client_lock ();
|
fifo_client_lock ();
|
||||||
for (int i = 0; i < nhandlers; i++)
|
for (int i = 0; i < nhandlers; i++)
|
||||||
fork_fixup (parent, fc_handler[i].h, "fc_handler[].h");
|
fork_fixup (parent, fc_handler[i].h, "fc_handler[].h");
|
||||||
@ -1087,6 +1174,8 @@ fhandler_fifo::fixup_after_exec ()
|
|||||||
/* Make sure the child starts unlocked. */
|
/* Make sure the child starts unlocked. */
|
||||||
fifo_client_unlock ();
|
fifo_client_unlock ();
|
||||||
|
|
||||||
|
if (reopen_shmem () < 0)
|
||||||
|
api_fatal ("Can't reopen shared memory during exec, %E");
|
||||||
if (!(cancel_evt = create_event ()))
|
if (!(cancel_evt = create_event ()))
|
||||||
api_fatal ("Can't create reader thread cancel event during exec, %E");
|
api_fatal ("Can't create reader thread cancel event during exec, %E");
|
||||||
if (!(thr_sync_evt = create_event ()))
|
if (!(thr_sync_evt = create_event ()))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user