| /* Windows32-based operating system interface for GNU Make. |
| Copyright (C) 2016 Free Software Foundation, Inc. |
| This file is part of GNU Make. |
| |
| GNU Make is free software; you can redistribute it and/or modify it under the |
| terms of the GNU General Public License as published by the Free Software |
| Foundation; either version 3 of the License, or (at your option) any later |
| version. |
| |
| GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "makeint.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <windows.h> |
| #include <process.h> |
| #include <io.h> |
| #include "pathstuff.h" |
| #include "sub_proc.h" |
| #include "w32err.h" |
| #include "os.h" |
| #include "debug.h" |
| |
| /* This section provides OS-specific functions to support the jobserver. */ |
| |
| static char jobserver_semaphore_name[MAX_PATH + 1]; |
| static HANDLE jobserver_semaphore = NULL; |
| |
| void |
| jobserver_setup (int slots) |
| { |
| /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects |
| * and one of them is the job-server semaphore object. Limit the |
| * number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */ |
| |
| if (slots >= MAXIMUM_WAIT_OBJECTS) |
| { |
| slots = MAXIMUM_WAIT_OBJECTS - 1; |
| DB (DB_JOBS, (_("Jobserver slots limited to %d\n"), slots)); |
| } |
| |
| sprintf (jobserver_semaphore_name, "gmake_semaphore_%d", _getpid ()); |
| |
| jobserver_semaphore = CreateSemaphore ( |
| NULL, /* Use default security descriptor */ |
| slots, /* Initial count */ |
| slots, /* Maximum count */ |
| jobserver_semaphore_name); /* Semaphore name */ |
| |
| if (jobserver_semaphore == NULL) |
| { |
| DWORD err = GetLastError (); |
| const char *estr = map_windows32_error_to_string (err); |
| ONS (fatal, NILF, |
| _("creating jobserver semaphore: (Error %ld: %s)"), err, estr); |
| } |
| } |
| |
| void |
| jobserver_parse_arg (const char* arg) |
| { |
| jobserver_semaphore = OpenSemaphore ( |
| SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */ |
| FALSE, /* Child processes DON'T inherit */ |
| arg); /* Semaphore name */ |
| |
| if (jobserver_semaphore == NULL) |
| { |
| DWORD err = GetLastError (); |
| const char *estr = map_windows32_error_to_string (err); |
| fatal (NILF, strlen (arg) + INTSTR_LENGTH + strlen (estr), |
| _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"), |
| arg, err, estr); |
| } |
| DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), arg)); |
| } |
| |
| char * |
| jobserver_get_arg () |
| { |
| char *fds = xmalloc (MAX_PATH + 1); |
| strcpy (fds, jobserver_semaphore_name); |
| return fds; |
| } |
| |
| unsigned int |
| jobserver_enabled () |
| { |
| return jobserver_semaphore != NULL; |
| } |
| |
| /* Close jobserver semaphore */ |
| void |
| jobserver_clear () |
| { |
| if (jobserver_semaphore != NULL) |
| { |
| CloseHandle (jobserver_semaphore); |
| jobserver_semaphore = NULL; |
| } |
| } |
| |
| void |
| jobserver_release (int is_fatal) |
| { |
| if (! ReleaseSemaphore ( |
| jobserver_semaphore, /* handle to semaphore */ |
| 1, /* increase count by one */ |
| NULL)) /* not interested in previous count */ |
| { |
| if (is_fatal) |
| { |
| DWORD err = GetLastError (); |
| const char *estr = map_windows32_error_to_string (err); |
| ONS (fatal, NILF, |
| _("release jobserver semaphore: (Error %ld: %s)"), err, estr); |
| } |
| perror_with_name ("release_jobserver_semaphore", ""); |
| } |
| } |
| |
| unsigned int |
| jobserver_acquire_all () |
| { |
| unsigned int tokens = 0; |
| while (1) |
| { |
| DWORD dwEvent = WaitForSingleObject ( |
| jobserver_semaphore, /* Handle to semaphore */ |
| 0); /* DON'T wait on semaphore */ |
| |
| if (dwEvent != WAIT_OBJECT_0) |
| return tokens; |
| |
| ++tokens; |
| } |
| } |
| |
| void |
| jobserver_signal () |
| { |
| } |
| |
| void jobserver_pre_child (int recursive) |
| { |
| } |
| |
| void jobserver_post_child (int recursive) |
| { |
| } |
| |
| void |
| jobserver_pre_acquire () |
| { |
| } |
| |
| /* Returns 1 if we got a token, or 0 if a child has completed. |
| The Windows implementation doesn't support load detection. */ |
| int |
| jobserver_acquire (int timeout) |
| { |
| HANDLE handles[MAXIMUM_WAIT_OBJECTS]; |
| DWORD dwHandleCount; |
| DWORD dwEvent; |
| |
| /* Add jobserver semaphore to first slot. */ |
| handles[0] = jobserver_semaphore; |
| |
| /* Build array of handles to wait for. */ |
| dwHandleCount = 1 + process_set_handles (&handles[1]); |
| |
| dwEvent = WaitForMultipleObjects ( |
| dwHandleCount, /* number of objects in array */ |
| handles, /* array of objects */ |
| FALSE, /* wait for any object */ |
| INFINITE); /* wait until object is signalled */ |
| |
| if (dwEvent == WAIT_FAILED) |
| { |
| DWORD err = GetLastError (); |
| const char *estr = map_windows32_error_to_string (err); |
| ONS (fatal, NILF, |
| _("semaphore or child process wait: (Error %ld: %s)"), |
| err, estr); |
| } |
| |
| /* WAIT_OBJECT_0 indicates that the semaphore was signalled. */ |
| return dwEvent == WAIT_OBJECT_0; |
| } |