1 /* Replacements for Posix functions and Posix functionality for MS-Windows.
3 Copyright (C) 2013 Free Software Foundation, Inc.
4 This file is part of GNU Make.
6 GNU Make is free software; you can redistribute it and/or modify it under the
7 terms of the GNU General Public License as published by the Free Software
8 Foundation; either version 3 of the License, or (at your option) any later
11 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along with
16 this program. If not, see <http://www.gnu.org/licenses/>. */
29 #ifndef NO_OUTPUT_SYNC
30 /* Support for OUTPUT_SYNC and related functionality. */
32 /* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */
34 fcntl (intptr_t fd, int cmd, ...)
44 /* Could have used GetHandleInformation, but that isn't
45 supported on Windows 9X. */
46 if (_get_osfhandle (fd) == -1)
51 void *buf = va_arg (ap, void *);
52 struct flock *fl = (struct flock *)buf;
53 HANDLE hmutex = (HANDLE)fd;
54 static struct flock last_fl;
55 short last_type = last_fl.l_type;
59 if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
71 if (last_type == F_WRLCK)
73 /* Don't call WaitForSingleObject if we already
74 own the mutex, because doing so will require
75 us to call ReleaseMutex an equal number of
76 times, before the mutex is actually
81 result = WaitForSingleObject (hmutex, INFINITE);
85 /* We don't care if the mutex owner crashed or
90 case WAIT_TIMEOUT: /* cannot happen, really */
92 DWORD err = GetLastError ();
94 /* Invalidate the last command. */
95 memset (&last_fl, 0, sizeof (last_fl));
99 case ERROR_INVALID_HANDLE:
100 case ERROR_INVALID_FUNCTION:
112 /* FIXME: Perhaps we should call ReleaseMutex
113 repatedly until it errors out, to make sure the
114 mutext is released even if we somehow managed to
115 to take ownership multiple times? */
116 BOOL status = ReleaseMutex (hmutex);
122 DWORD err = GetLastError ();
124 if (err == ERROR_NOT_OWNER)
128 memset (&last_fl, 0, sizeof (last_fl));
146 static intptr_t mutex_handle = -1;
148 /* Record in a static variable the mutex handle we were requested to
149 use. That nameless mutex was created by the top-level Make, and
150 its handle was passed to us via inheritance. The value of that
151 handle is passed via the command-line arguments, so that we know
152 which handle to use. */
154 record_sync_mutex (const char *str)
157 intptr_t hmutex = strtol (str, &endp, 16);
160 mutex_handle = hmutex;
168 /* Create a new mutex or reuse one created by our parent. */
172 SECURITY_ATTRIBUTES secattr;
173 intptr_t hmutex = -1;
175 /* If we have a mutex handle passed from the parent Make, just use
177 if (mutex_handle > 0)
180 /* We are the top-level Make, and we want the handle to be inherited
181 by our child processes. */
182 secattr.nLength = sizeof (secattr);
183 secattr.lpSecurityDescriptor = NULL; /* use default security descriptor */
184 secattr.bInheritHandle = TRUE;
186 hmutex = (intptr_t)CreateMutex (&secattr, FALSE, NULL);
189 DWORD err = GetLastError ();
191 fprintf (stderr, "CreateMutex: error %lu\n", err);
196 mutex_handle = hmutex;
200 /* Return non-zero if F1 and F2 are 2 streams representing the same
201 file or pipe or device. */
203 same_stream (FILE *f1, FILE *f2)
205 HANDLE fh1 = (HANDLE)_get_osfhandle (fileno (f1));
206 HANDLE fh2 = (HANDLE)_get_osfhandle (fileno (f2));
208 /* Invalid file descriptors get treated as different streams. */
209 if (fh1 && fh1 != INVALID_HANDLE_VALUE
210 && fh2 && fh2 != INVALID_HANDLE_VALUE)
216 DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2);
219 || ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN)
221 else if (ftyp1 == FILE_TYPE_CHAR)
223 /* For character devices, check if they both refer to a
224 console. This loses if both handles refer to the
225 null device (FIXME!), but in that case we don't care
226 in the context of Make. */
227 DWORD conmode1, conmode2;
229 /* Each process on Windows can have at most 1 console,
230 so if both handles are for the console device, they
231 are the same. We also compare the console mode to
232 distinguish between stdin and stdout/stderr. */
233 if (GetConsoleMode (fh1, &conmode1)
234 && GetConsoleMode (fh2, &conmode2)
235 && conmode1 == conmode2)
240 /* For disk files and pipes, compare their unique
242 BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
244 /* Pipes get zero in the volume serial number, but do
245 appear to have meaningful information in file index
246 attributes. We test file attributes as well, for a
248 if (GetFileInformationByHandle (fh1, &bhfi1)
249 && GetFileInformationByHandle (fh2, &bhfi2))
250 return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
251 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow
252 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
253 && bhfi1.dwFileAttributes == bhfi2.dwFileAttributes);
260 /* A replacement for tmpfile, since the MSVCRT implementation creates
261 the file in the root directory of the current drive, which might
262 not be writable by our user. Most of the code borrowed from
263 create_batch_file, see job.c. */
267 char temp_path[MAXPATHLEN];
268 unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
270 /* The following variable is static so we won't try to reuse a name
271 that was generated a little while ago, because that file might
272 not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below,
273 which tells the OS it doesn't need to flush the cache to disk.
274 If the file is not yet on disk, we might think the name is
275 available, while it really isn't. This happens in parallel
276 builds, where Make doesn't wait for one job to finish before it
277 launches the next one. */
278 static unsigned uniq = 0;
279 static int second_loop = 0;
280 const char base[] = "gmake_tmpf";
281 const unsigned sizemax = sizeof base - 1 + 4 + 10 + 10;
282 unsigned pid = GetCurrentProcessId ();
286 path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
291 if (uniq >= 0x10000 && !second_loop)
293 /* If we already had 64K batch files in this
294 process, make a second loop through the numbers,
295 looking for free slots, i.e. files that were
296 deleted in the meantime. */
300 while (path_size > 0 &&
301 path_size + sizemax < sizeof temp_path &&
302 !(uniq >= 0x10000 && second_loop))
306 sprintf (temp_path + path_size,
308 temp_path[path_size - 1] == '\\' ? "" : "\\",
310 h = CreateFile (temp_path, /* file name */
311 GENERIC_READ | GENERIC_WRITE | DELETE, /* desired access */
312 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
313 NULL, /* default security attributes */
314 CREATE_NEW, /* creation disposition */
315 FILE_ATTRIBUTE_NORMAL | /* flags and attributes */
316 FILE_ATTRIBUTE_TEMPORARY |
317 FILE_FLAG_DELETE_ON_CLOSE,
318 NULL); /* no template file */
320 if (h == INVALID_HANDLE_VALUE)
322 const DWORD er = GetLastError ();
324 if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS)
327 if (uniq == 0x10000 && !second_loop)
334 /* The temporary path is not guaranteed to exist, or might
335 not be writable by user. Use the current directory as
337 else if (path_is_dot == 0)
339 path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
351 int fd = _open_osfhandle ((intptr_t)h, 0);
353 return _fdopen (fd, "w+b");
362 #endif /* !NO_OUTPUT_SYNC */
366 /* Support for dynamic loading of objects. */
369 static DWORD last_err;
372 dlopen (const char *file, int mode)
374 char dllfn[MAX_PATH], *p;
377 if ((mode & ~(RTLD_LAZY | RTLD_NOW | RTLD_GLOBAL)) != 0)
380 last_err = ERROR_INVALID_PARAMETER;
385 dllhandle = GetModuleHandle (NULL);
388 /* MSDN says to be sure to use backslashes in the DLL file name. */
389 strcpy (dllfn, file);
390 for (p = dllfn; *p; p++)
394 dllhandle = LoadLibrary (dllfn);
397 last_err = GetLastError ();
405 static char errbuf[1024];
411 ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
412 | FORMAT_MESSAGE_IGNORE_INSERTS,
413 NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
414 while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r'))
419 sprintf (errbuf, "Error code %lu", last_err);
426 dlsym (void *handle, const char *name)
430 if (!handle || handle == INVALID_HANDLE_VALUE)
432 last_err = ERROR_INVALID_PARAMETER;
436 addr = GetProcAddress (handle, name);
438 last_err = GetLastError ();
444 dlclose (void *handle)
446 if (!handle || handle == INVALID_HANDLE_VALUE)
448 if (!FreeLibrary (handle))
455 #endif /* MAKE_LOAD */