4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-21 00:07:36 +08:00

forkables: simplify disabling via shm

* Rename cygwin_shared->prefer_forkable_hardlinks to
  forkable_hardlink_support, with values
  0 for Unknown, 1 for Supported, -1 for Unsupported.
  Upon first dll loaded ever, dll_list::forkable_ntnamesize checks the
  /var/run/cygfork directory to both exist and reside on NTFS, setting
  cygwin_shared->forkable_hardlink_support accordingly.
* Replace enum forkables_needs by bool forkables_created: Set
  to True by request_forkables after creating forkable hardlinks.
This commit is contained in:
Michael Haubenwallner 2017-03-01 10:19:37 +01:00 committed by Corinna Vinschen
parent 8bbb3d3a23
commit 135577f708
5 changed files with 65 additions and 148 deletions

View File

@ -87,17 +87,9 @@ struct dll
class dll_list
{
/* forkables */
enum
{
forkables_unknown,
forkables_impossible,
forkables_disabled,
forkables_needless,
forkables_needed,
forkables_created,
}
forkables_needs;
bool forkables_supported ();
DWORD forkables_dirx_size;
bool forkables_created;
PWCHAR forkables_dirx_ntname;
PWCHAR forkables_mutex_name;
HANDLE forkables_mutex;
@ -160,10 +152,11 @@ public:
void cleanup_forkables ();
bool setup_forkables (bool with_forkables)
{
if (forkables_needs == forkables_impossible)
return true; /* short cut to not retry fork */
/* Once used, always use forkables in current process chain. */
if (forkables_needs != forkables_unknown)
if (!forkables_supported ())
return true; /* no need to retry fork */
if (forkables_created)
/* Once created, use forkables in current
process chain on first fork try already. */
with_forkables = true;
if (with_forkables)
request_forkables ();

View File

@ -501,17 +501,56 @@ dll::create_forkable ()
return false;
}
bool
dll_list::forkables_supported ()
{
return cygwin_shared->forkable_hardlink_support >= 0;
}
/* return the number of characters necessary to store one forkable name */
size_t
dll_list::forkable_ntnamesize (dll_type type, PCWCHAR fullntname, PCWCHAR modname)
{
/* per process, this is the first forkables-method ever called */
if (forkables_needs == forkables_unknown &&
!cygwin_shared->prefer_forkable_hardlinks)
forkables_needs = forkables_impossible; /* short cut */
if (cygwin_shared->forkable_hardlink_support == 0) /* Unknown */
{
/* check existence of forkables dir */
PWCHAR pbuf = nt_max_path_buf ();
for (namepart const *part = forkable_nameparts; part->text; ++part)
{
if (part->textfunc)
pbuf += part->textfunc (pbuf, -1);
else
pbuf += __small_swprintf (pbuf, L"%W", part->text);
if (part->mutex_from_dir)
break; /* up to first mutex-naming dir */
}
pbuf = nt_max_path_buf ();
if (forkables_needs == forkables_impossible)
return 0;
UNICODE_STRING fn;
RtlInitUnicodeString (&fn, pbuf);
HANDLE dh = INVALID_HANDLE_VALUE;
fs_info fsi;
if (fsi.update (&fn, NULL) &&
/* FIXME: !fsi.is_readonly () && */
fsi.is_ntfs ())
dh = ntopenfile (pbuf, NULL, FILE_DIRECTORY_FILE);
if (dh != INVALID_HANDLE_VALUE)
{
cygwin_shared->forkable_hardlink_support = 1; /* Yes */
NtClose (dh);
debug_printf ("enabled");
}
else
{
cygwin_shared->forkable_hardlink_support = -1; /* No */
debug_printf ("disabled, missing or not on NTFS %W", fn.Buffer);
}
}
if (!forkables_supported ())
return 0;
if (!forkables_dirx_size)
{
@ -560,9 +599,6 @@ dll_list::forkable_ntnamesize (dll_type type, PCWCHAR fullntname, PCWCHAR modnam
void
dll_list::prepare_forkables_nomination ()
{
if (!forkables_dirx_ntname)
return;
dll *d = &dlls.start;
while ((d = d->next))
stat_real_file_once (d); /* uses nt_max_path_buf () */
@ -627,106 +663,19 @@ dll_list::prepare_forkables_nomination ()
void
dll_list::update_forkables_needs ()
{
dll *d;
if (forkables_needs == forkables_unknown)
{
/* check if filesystem of forkables dir is NTFS */
PWCHAR pbuf = nt_max_path_buf ();
for (namepart const *part = forkable_nameparts; part->text; ++part)
{
if (part->mutex_from_dir)
break; /* leading non-mutex-naming dirs, must exist anyway */
if (part->textfunc)
pbuf += part->textfunc (pbuf, -1);
else
pbuf += __small_swprintf (pbuf, L"%W", part->text);
}
UNICODE_STRING fn;
RtlInitUnicodeString (&fn, nt_max_path_buf ());
fs_info fsi;
if (fsi.update (&fn, NULL) &&
/* FIXME: !fsi.is_readonly () && */
fsi.is_ntfs ())
forkables_needs = forkables_disabled; /* check directory itself */
else
{
debug_printf ("impossible, not on NTFS %W", fn.Buffer);
forkables_needs = forkables_impossible;
cygwin_shared->prefer_forkable_hardlinks = 0;
}
}
if (forkables_needs == forkables_impossible)
return; /* we have not created any hardlink, nothing to clean up */
if (forkables_needs == forkables_disabled ||
forkables_needs == forkables_needless ||
forkables_needs == forkables_created)
{
/* (re-)check existence of forkables dir */
PWCHAR pbuf = nt_max_path_buf ();
for (namepart const *part = forkable_nameparts; part->text; ++part)
{
if (part->textfunc)
pbuf += part->textfunc (pbuf, -1);
else
pbuf += __small_swprintf (pbuf, L"%W", part->text);
if (part->mutex_from_dir)
break; /* up to first mutex-naming dir */
}
pbuf = nt_max_path_buf ();
HANDLE dh = ntopenfile (pbuf, NULL, FILE_DIRECTORY_FILE);
if (dh != INVALID_HANDLE_VALUE)
{
NtClose (dh);
if (forkables_needs == forkables_disabled)
forkables_needs = forkables_needless;
}
else if (forkables_needs != forkables_disabled)
{
debug_printf ("disabled, disappearing %W", pbuf);
close_mutex ();
denominate_forkables ();
forkables_needs = forkables_disabled;
}
else
debug_printf ("disabled, missing %W", pbuf);
}
if (forkables_needs == forkables_disabled)
return;
if (forkables_needs == forkables_created)
if (forkables_created)
{
/* already have created hardlinks in this process, ... */
forkables_needs = forkables_needless;
d = &start;
dll *d = &start;
while ((d = d->next) != NULL)
if (d->forkable_ntname && !*d->forkable_ntname)
{
/* ... but another dll was loaded since last fork */
debug_printf ("needed, since last fork loaded %W", d->ntname);
forkables_needs = forkables_needed;
forkables_created = false;
break;
}
}
if (forkables_needs > forkables_needless)
return; /* no need to check anything else */
if (forkables_needs != forkables_needless)
{
/* paranoia */
system_printf ("WARNING: invalid forkables_needs value %d",
forkables_needs);
return;
}
forkables_needs = forkables_needed;
}
/* Create the nominated forkable hardlinks and directories as necessary,
@ -958,7 +907,7 @@ dll_list::close_mutex ()
void
dll_list::cleanup_forkables ()
{
if (!forkables_dirx_ntname)
if (!forkables_supported ())
return;
bool locked = close_mutex ();
@ -1034,58 +983,32 @@ dll_list::set_forkables_inheritance (bool inherit)
void
dll_list::request_forkables ()
{
if (!forkables_dirx_ntname)
if (!forkables_supported ())
return;
/* Even on forkables_impossible, keep the number of open handles
stable across the fork, and close them when releasing only. */
prepare_forkables_nomination ();
update_forkables_needs ();
set_forkables_inheritance (true);
if (forkables_needs == forkables_disabled)
{
/* we do not support (re-)enabling on the fly */
forkables_needs = forkables_impossible;
cygwin_shared->prefer_forkable_hardlinks = 0;
}
if (forkables_needs <= forkables_needless)
return;
if (forkables_created)
return; /* nothing new to create */
dll *d = &start;
while ((d = d->next))
d->nominate_forkable (forkables_dirx_ntname);
bool updated = update_forkables ();
if (!updated)
forkables_needs = forkables_needless;
else
forkables_needs = forkables_created;
if (update_forkables ())
forkables_created = true;
}
void
dll_list::release_forkables ()
{
if (!forkables_dirx_ntname)
if (!forkables_supported ())
return;
set_forkables_inheritance (false);
if (forkables_needs == forkables_impossible)
{
cleanup_forkables ();
dll *d = &start;
while ((d = d->next))
d->forkable_ntname = NULL;
cfree (forkables_dirx_ntname);
forkables_dirx_ntname = NULL;
forkables_mutex_name = NULL;
}
}

View File

@ -518,7 +518,7 @@ details. */
regions. It is incremented when incompatible changes are made to the shared
memory region *or* to any named shared mutexes, semaphores, etc. */
#define CYGWIN_VERSION_SHARED_DATA 6
#define CYGWIN_VERSION_SHARED_DATA 5
/* An identifier used in the names used to create shared objects. The full
names include the CYGWIN_VERSION_SHARED_DATA version as well as this

View File

@ -334,6 +334,7 @@ shared_info::initialize ()
NtAllocateLocallyUniqueId (&luid);/* Initialize pid_src to a low */
InterlockedExchange (&pid_src, /* random value to make start pid */
luid.LowPart % 2048);/* less predictably */
forkable_hardlink_support = 0; /* 0: Unknown, 1: Yes, -1: No */
/* Defer debug output printing the installation root and installation key
up to this point. Debug output except for system_printf requires
the global shared memory to exist. */

View File

@ -33,7 +33,7 @@ public:
/* Data accessible to all tasks */
#define CURR_SHARED_MAGIC 0x3a6025edU
#define CURR_SHARED_MAGIC 0xc590e67eU
#define USER_VERSION 1
@ -51,7 +51,7 @@ class shared_info
mtinfo mt;
loadavginfo loadavg;
LONG pid_src;
char prefer_forkable_hardlinks; /* single byte access always is atomic */
char forkable_hardlink_support; /* single byte access always is atomic */
void initialize ();
void init_obcaseinsensitive ();