1 /* shared.cc: shared data area support.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "miscfuncs.h"
19 #include "shared_info_magic.h"
21 #include "cygwin_version.h"
22 #include "memory_layout.h"
27 shared_info NO_COPY
*cygwin_shared
;
28 user_info NO_COPY
*user_shared
;
29 HANDLE NO_COPY cygwin_shared_h
;
30 HANDLE NO_COPY cygwin_user_h
;
32 /* This function returns a handle to the top-level directory in the global
33 NT namespace used to implement global objects including shared memory. */
35 static HANDLE NO_COPY shared_parent_dir
;
38 get_shared_parent_dir ()
41 OBJECT_ATTRIBUTES attr
;
44 if (!shared_parent_dir
)
46 WCHAR bnoname
[MAX_PATH
];
47 __small_swprintf (bnoname
, L
"\\BaseNamedObjects\\%s%s-%S",
48 cygwin_version
.shared_id
,
49 _cygwin_testing
? cygwin_version
.dll_build_date
: "",
50 &cygheap
->installation_key
);
51 RtlInitUnicodeString (&uname
, bnoname
);
52 InitializeObjectAttributes (&attr
, &uname
, OBJ_OPENIF
, NULL
,
53 everyone_sd (CYG_SHARED_DIR_ACCESS
));
54 status
= NtCreateDirectoryObject (&shared_parent_dir
,
55 CYG_SHARED_DIR_ACCESS
, &attr
);
56 if (!NT_SUCCESS (status
))
57 api_fatal ("NtCreateDirectoryObject(%S): %y", &uname
, status
);
59 return shared_parent_dir
;
62 static HANDLE NO_COPY session_parent_dir
;
65 get_session_parent_dir ()
68 OBJECT_ATTRIBUTES attr
;
71 if (!session_parent_dir
)
73 PROCESS_SESSION_INFORMATION psi
;
74 status
= NtQueryInformationProcess (NtCurrentProcess (),
75 ProcessSessionInformation
,
76 &psi
, sizeof psi
, NULL
);
77 if (!NT_SUCCESS (status
) || psi
.SessionId
== 0)
78 session_parent_dir
= get_shared_parent_dir ();
81 WCHAR bnoname
[MAX_PATH
];
82 __small_swprintf (bnoname
,
83 L
"\\Sessions\\BNOLINKS\\%d\\%s%s-%S",
84 psi
.SessionId
, cygwin_version
.shared_id
,
85 _cygwin_testing
? cygwin_version
.dll_build_date
: "",
86 &cygheap
->installation_key
);
87 RtlInitUnicodeString (&uname
, bnoname
);
88 InitializeObjectAttributes (&attr
, &uname
, OBJ_OPENIF
, NULL
,
89 everyone_sd(CYG_SHARED_DIR_ACCESS
));
90 status
= NtCreateDirectoryObject (&session_parent_dir
,
91 CYG_SHARED_DIR_ACCESS
, &attr
);
92 if (!NT_SUCCESS (status
))
93 api_fatal ("NtCreateDirectoryObject(%S): %y", &uname
, status
);
96 return session_parent_dir
;
100 shared_name (char *ret_buf
, const char *str
, int num
)
102 __small_sprintf (ret_buf
, "%s.%d", str
, num
);
107 shared_name (WCHAR
*ret_buf
, const WCHAR
*str
, int num
)
109 __small_swprintf (ret_buf
, L
"%W.%d", str
, num
);
113 #define page_const ((ptrdiff_t) 65535)
114 #define pround(n) ((ptrdiff_t)(((n) + page_const) & ~page_const))
116 static NO_COPY
uintptr_t next_address
= SHARED_REGIONS_ADDRESS_LOW
;
119 open_shared (const WCHAR
*name
, int n
, HANDLE
& shared_h
, DWORD size
,
120 shared_locations m
, PSECURITY_ATTRIBUTES psa
, DWORD access
)
123 return open_shared (name
, n
, shared_h
, size
, m
, created_dummy
, psa
, access
);
127 open_shared (const WCHAR
*name
, int n
, HANDLE
& shared_h
, DWORD size
,
128 shared_locations m
, bool &created
, PSECURITY_ATTRIBUTES psa
,
131 WCHAR map_buf
[MAX_PATH
];
132 WCHAR
*mapname
= NULL
;
140 mapname
= shared_name (map_buf
, name
, n
);
141 if (m
== SH_JUSTOPEN
)
142 shared_h
= OpenFileMappingW (access
, FALSE
, mapname
);
146 shared_h
= CreateFileMappingW (INVALID_HANDLE_VALUE
, psa
,
147 PAGE_READWRITE
, 0, size
, mapname
);
148 if (GetLastError () == ERROR_ALREADY_EXISTS
)
153 else if (m
!= SH_JUSTOPEN
)
154 api_fatal ("CreateFileMapping %W, %E. Terminating.", mapname
);
159 /* Locate shared regions in the area between SHARED_REGIONS_ADDRESS_LOW
160 and SHARED_REGIONS_ADDRESS_HIGH, retrying until we have a slot.
161 Don't use MapViewOfFile3 (STATUS_DLL_INIT_FAILED during fork). */
166 addr
= (void *) next_address
;
167 shared
= MapViewOfFileEx (shared_h
, access
, 0, 0, 0, addr
);
168 next_address
+= wincap
.allocation_granularity ();
169 if (next_address
>= SHARED_REGIONS_ADDRESS_HIGH
)
173 next_address
= SHARED_REGIONS_ADDRESS_LOW
;
180 api_fatal ("MapViewOfFileEx '%W'(%p, size %u, m %d, created %d), %E. "
181 "Terminating.", mapname
, shared_h
, size
, m
, created
);
183 debug_printf ("name %W, shared %p (wanted %p), h %p, m %d, created %d",
184 mapname
, shared
, addr
, shared_h
, m
, created
);
189 /* Second half of user shared initialization: Initialize content. */
191 user_info::initialize ()
193 /* Wait for initialization of the Cygwin per-user shared, if necessary */
194 spinlock
sversion (version
, CURR_USER_MAGIC
);
197 cb
= sizeof (*user_shared
);
198 /* Initialize mount table from system fstab prior to calling
199 internal_getpwsid. This allows to convert pw_dir and pw_shell
200 paths given in DOS notation to valid POSIX paths. */
201 mountinfo
.init (false);
202 cygpsid
sid (cygheap
->user
.sid ());
203 struct passwd
*pw
= internal_getpwsid (sid
);
204 /* Correct the user name with what's defined in /etc/passwd before
205 loading the user fstab file. */
207 cygheap
->user
.set_name (pw
->pw_name
);
208 /* After fetching the user infos, add mount entries from user's fstab. */
209 mountinfo
.init (true);
211 else if (sversion
!= CURR_USER_MAGIC
)
212 sversion
.multiple_cygwin_problem ("user shared memory version", version
,
214 else if (user_shared
->cb
!= sizeof (*user_shared
))
215 sversion
.multiple_cygwin_problem ("user shared memory size", cb
,
216 sizeof (*user_shared
));
219 /* First half of user shared initialization: Create shared mem region. */
221 user_info::create (bool reinit
)
223 WCHAR name
[UNLEN
+ 1] = L
""; /* Large enough for SID */
227 if (!UnmapViewOfFile (user_shared
))
228 debug_printf("UnmapViewOfFile %E");
229 if (!ForceCloseHandle (cygwin_user_h
))
230 debug_printf("CloseHandle %E");
231 cygwin_user_h
= NULL
;
235 cygheap
->user
.get_windows_id (name
);
237 user_shared
= (user_info
*) open_shared (name
, USER_VERSION
,
238 cygwin_user_h
, sizeof (user_info
),
239 SH_USER_SHARED
, &sec_none
);
240 debug_printf ("opening user shared for '%W' at %p", name
, user_shared
);
241 ProtectHandleINH (cygwin_user_h
);
242 debug_printf ("user shared version %x", user_shared
->version
);
244 user_shared
->initialize ();
245 cygheap
->shared_regions
.user_shared_addr
= user_shared
;
251 ForceCloseHandle (cygwin_shared_h
);
252 UnmapViewOfFile (cygwin_shared
);
253 ForceCloseHandle (cygwin_user_h
);
254 UnmapViewOfFile (user_shared
);
257 /* Initialize obcaseinsensitive.*/
259 shared_info::init_obcaseinsensitive ()
261 /* Instead of reading the obcaseinsensitive registry value, test the
262 actual state of case sensitivity handling in the kernel. */
263 UNICODE_STRING sysroot
;
264 OBJECT_ATTRIBUTES attr
;
267 RtlInitUnicodeString (&sysroot
, L
"\\SYSTEMROOT");
268 InitializeObjectAttributes (&attr
, &sysroot
, 0, NULL
, NULL
);
269 /* NtOpenSymbolicLinkObject returns STATUS_ACCESS_DENIED when called
270 with a 0 access mask. However, if the kernel is case sensitive,
271 it returns STATUS_OBJECT_NAME_NOT_FOUND because we used the incorrect
272 case for the filename (It's actually "\\SystemRoot"). */
273 obcaseinsensitive
= NtOpenSymbolicLinkObject (&h
, 0, &attr
)
274 != STATUS_OBJECT_NAME_NOT_FOUND
;
278 shared_info::create ()
280 cygwin_shared
= (shared_info
*) open_shared (L
"shared",
281 CYGWIN_VERSION_SHARED_DATA
,
283 sizeof (*cygwin_shared
),
286 cygwin_shared
->initialize ();
287 cygheap
->shared_regions
.cygwin_shared_addr
= cygwin_shared
;
291 shared_info::initialize ()
293 spinlock
sversion (version
, CURR_SHARED_MAGIC
);
299 get_session_parent_dir (); /* Create session dir if first process. */
300 init_obcaseinsensitive (); /* Initialize obcaseinsensitive */
301 tty
.init (); /* Initialize tty table */
302 mt
.initialize (); /* Initialize shared tape information */
303 loadavg
.initialize (); /* Initialize loadavg information */
304 NtAllocateLocallyUniqueId (&luid
);/* Initialize pid_src to a low */
305 InterlockedExchange (&pid_src
, /* random value to make start pid */
306 luid
.LowPart
% 2048);/* less predictably */
307 forkable_hardlink_support
= 0; /* 0: Unknown, 1: Yes, -1: No */
308 /* Defer debug output printing the installation root and installation key
309 up to this point. Debug output except for system_printf requires
310 the global shared memory to exist. */
311 debug_printf ("Installation root: <%W> key: <%S>",
312 cygheap
->installation_root
, &cygheap
->installation_key
);
314 else if (sversion
!= CURR_SHARED_MAGIC
)
315 sversion
.multiple_cygwin_problem ("system shared memory version",
316 sversion
, CURR_SHARED_MAGIC
);
317 else if (cb
!= sizeof (*this))
318 system_printf ("size of shared memory region changed from %lu to %u",
325 shared_info::create (); /* Initialize global shared memory */
326 cygheap
->user_heap
.init (); /* Initialize user heap */
327 user_info::create (false); /* Initialize per-user shared memory */
328 /* Initialize tty list session stuff. Doesn't really belong here but
329 this needs to be initialized before any tty or console manipulation
330 happens and it is a common location. */
331 tty_list::init_session ();