Changeset 2843 in kBuild
- Timestamp:
- Aug 28, 2016 3:31:02 PM (9 years ago)
- Location:
- trunk/src/kmk
- Files:
-
- 2 added
- 1 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/Makefile.kmk
r2816 r2843 129 129 getloadavg.c \ 130 130 w32/subproc/misc.c \ 131 w32/subproc/sub_proc.c \132 131 w32/subproc/w32err.c \ 133 132 w32/pathstuff.c \ … … 245 244 kbuild-object.c 246 245 246 kmk_SOURCES.win = \ 247 w32/subproc/sub_proc.c 248 247 249 kmk_DEFS.freebsd.x86 = CONFIG_WITHOUT_THREADS 248 250 … … 276 278 kmkbuiltin/rm.c \ 277 279 kmkbuiltin/rmdir.c \ 280 kmkbuiltin/kSubmit.c \ 278 281 kmkbuiltin/sleep.c \ 279 282 kmkbuiltin/test.c \ … … 459 462 vpath.c \ 460 463 remote-stub.c 464 465 kmk_gmake_SOURCES.win = \ 466 w32/subproc/sub_proc.c 461 467 462 468 … … 510 516 remote-stub.c 511 517 518 kmk_fgmake_SOURCES.win = \ 519 w32/subproc/sub_proc.c 520 512 521 513 522 include $(FILE_KBUILD_SUB_FOOTER) … … 545 554 $(kmk_0_OUTDIR)/grp.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) 546 555 $(ECHO_EXT) > $@ 556 557 558 ifeq ($(KBUILD_TARGET),win) 559 # 560 # tstFileInfo 561 # 562 PROGRAMS.win += tstFileInfo 563 tstFileInfo_TEMPLATE = BIN 564 tstFileInfo_SOURCES = w32/tstFileInfo.c 565 endif 547 566 548 567 -
trunk/src/kmk/config.h.win
r2766 r2843 443 443 444 444 /* Define to `int' if <sys/types.h> does not define. */ 445 #define pid_t int 445 /* Note (bird)! sub_proc.c needs this to be pointer sized. */ 446 #define pid_t intptr_t 446 447 447 448 /* Define to `int' if <sys/types.h> doesn't define. */ -
trunk/src/kmk/job.c
r2754 r2843 1320 1320 child->pid = 0; 1321 1321 if (p2 != argv) 1322 rc = kmk_builtin_command (*p2, &argv_spawn, &child->pid );1322 rc = kmk_builtin_command (*p2, &argv_spawn, &child->pid, child); 1323 1323 else 1324 1324 { … … 1326 1326 while (argv[argc]) 1327 1327 argc++; 1328 rc = kmk_builtin_command_parsed (argc, argv, &argv_spawn, &child->pid );1328 rc = kmk_builtin_command_parsed (argc, argv, &argv_spawn, &child->pid, child); 1329 1329 } 1330 1330 -
trunk/src/kmk/kmkbuiltin.c
r2591 r2843 43 43 #endif 44 44 45 int kmk_builtin_command(const char *pszCmd, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)45 int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned) 46 46 { 47 47 int argc; … … 155 155 */ 156 156 if (!*pszCmd) 157 rc = kmk_builtin_command_parsed(argc, argv, p papszArgvToSpawn, pPidSpawned);157 rc = kmk_builtin_command_parsed(argc, argv, pChild, ppapszArgvToSpawn, pPidSpawned); 158 158 else 159 159 rc = 1; … … 167 167 168 168 169 int kmk_builtin_command_parsed(int argc, char **argv, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)169 int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned) 170 170 { 171 171 const char *pszCmd = argv[0]; 172 int i umask;172 int iUmask; 173 173 int rc; 174 174 … … 184 184 185 185 /* 186 * String switch on the command .187 */ 188 i umask = umask(0);189 umask(i umask);186 * String switch on the command (frequent stuff at the top). 187 */ 188 iUmask = umask(0); 189 umask(iUmask); 190 190 if (!strcmp(pszCmd, "append")) 191 191 rc = kmk_builtin_append(argc, argv, environ); … … 198 198 else if (!strcmp(pszCmd, "kDepIDB")) 199 199 rc = kmk_builtin_kDepIDB(argc, argv, environ); 200 #ifdef KBUILD_OS_WINDOWS 201 else if (!strcmp(pszCmd, "kSubmit")) 202 rc = kmk_builtin_kSubmit(argc, argv, environ, pChild, pPidSpawned); 203 #endif 200 204 else if (!strcmp(pszCmd, "mkdir")) 201 205 rc = kmk_builtin_mkdir(argc, argv, environ); … … 239 243 */ 240 244 g_progname = "kmk"; /* paranoia, make sure it's not pointing at a freed argv[0]. */ 241 umask(i umask);245 umask(iUmask); 242 246 243 247 … … 261 265 262 266 *ppapszArgvToSpawn = NULL; 263 rc = kmk_builtin_command_parsed(argc_new, argv_new, p papszArgvToSpawn, pPidSpawned);267 rc = kmk_builtin_command_parsed(argc_new, argv_new, pChild, ppapszArgvToSpawn, pPidSpawned); 264 268 265 269 free(argv_new[0]); -
trunk/src/kmk/kmkbuiltin.h
r2736 r2843 5 5 6 6 /* 7 * Copyright (c) 2005-201 0knut st. osmundsen <[email protected]>7 * Copyright (c) 2005-2016 knut st. osmundsen <[email protected]> 8 8 * 9 9 * This file is part of kBuild. … … 24 24 */ 25 25 26 #ifndef ___kmk_kmkbuiltin_h___ 27 #define ___kmk_kmkbuiltin_h___ 28 26 29 #ifdef _MSC_VER 27 30 # ifndef pid_t /* see config.h.win */ 28 # define pid_t int 31 # define pid_t intptr_t /* Note! sub_proc.c needs it to be pointer sized. */ 29 32 # endif 30 33 #else … … 32 35 #endif 33 36 34 int kmk_builtin_command(const char *pszCmd, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);35 int kmk_builtin_command_parsed(int argc, char **argv, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);37 int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned); 38 int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned); 36 39 37 40 extern int kmk_builtin_append(int argc, char **argv, char **envp); … … 56 59 #endif 57 60 ); 61 #ifdef KBUILD_OS_WINDOWS 62 extern int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned); 63 extern int kSubmitSubProcGetResult(intptr_t pvUser, int *prcExit, int *piSigNo); 64 extern int kSubmitSubProcKill(intptr_t pvUser, int iSignal); 65 #endif 58 66 extern int kmk_builtin_kDepIDB(int argc, char **argv, char **envp); 59 67 extern int kmk_builtin_kDepObj(int argc, char **argv, char **envp); … … 63 71 extern int kbuild_version(const char *); 64 72 73 #endif 74 -
trunk/src/kmk/kmkbuiltin/kSubmit.c
r2842 r2843 50 50 # include <unistd.h> 51 51 #endif 52 #ifdef KBUILD_OS_WINDOWS 53 # include "sub_proc.h" 54 #endif 52 55 53 56 #include "kbuild.h" … … 79 82 /** The process ID of the kWorker process. */ 80 83 pid_t pid; 84 union 85 { 86 struct 87 { 88 /** The exit code. */ 89 int32_t rcExit; 90 /** Set to 1 if the worker is exiting. */ 91 uint8_t bWorkerExiting; 92 uint8_t abUnused[3]; 93 } s; 94 uint8_t ab[8]; 95 } Result; 96 /** Number of result bytes read alread. */ 97 size_t cbResultRead; 98 81 99 #ifdef KBUILD_OS_WINDOWS 82 100 /** The process handle. */ … … 86 104 /** For overlapped read (have valid event semaphore). */ 87 105 OVERLAPPED OverlappedRead; 88 /** The 32-bit exit code read bufffer. */89 uint32_t u32ReadResult;90 106 #else 91 107 /** The socket descriptor we use to talk to the kWorker process. */ … … 126 142 static unsigned g_uWorkerSeqNo = 0; 127 143 #endif 144 /** Set if we've registred the atexit handler already. */ 145 static int g_fAtExitRegistered = 0; 128 146 129 147 /** @var g_cArchBits … … 150 168 151 169 170 152 171 /** 153 172 * Unlinks a worker instance from a list. … … 219 238 220 239 pList->cEntries++; 240 } 241 242 243 /** 244 * Remove worker from the process ID hash table. 245 * 246 * @param pWorker The worker. 247 */ 248 static void kSubmitPidHashRemove(PWORKERINSTANCE pWorker) 249 { 250 size_t idxHash = KWORKER_PID_HASH(pWorker->pid); 251 if (g_apPidHash[idxHash] == pWorker) 252 g_apPidHash[idxHash] = pWorker->pNext; 253 else 254 { 255 PWORKERINSTANCE pPrev = g_apPidHash[idxHash]; 256 while (pPrev && pPrev->pNext != pWorker) 257 pPrev = pPrev->pNext; 258 assert(pPrev != NULL); 259 if (pPrev) 260 pPrev->pNext = pWorker->pNext; 261 } 262 pWorker->pid = -1; 221 263 } 222 264 … … 384 426 static int kSubmitRespawnWorker(PWORKERINSTANCE pWorker, int cVerbosity) 385 427 { 386 size_t idxHash;387 388 428 /* 389 429 * Clean up after the old worker. … … 394 434 /* Close the pipe handle first, breaking the pipe in case it's not already 395 435 busted up. Close the event semaphore too before waiting for the process. */ 396 if (!CloseHandle(pWorker->hPipe)) 397 warnx("CloseHandle(pWorker->hPipe): %u", GetLastError()); 398 pWorker->hPipe = INVALID_HANDLE_VALUE; 436 if (pWorker->hPipe != INVALID_HANDLE_VALUE) 437 { 438 if (!CloseHandle(pWorker->hPipe)) 439 warnx("CloseHandle(pWorker->hPipe): %u", GetLastError()); 440 pWorker->hPipe = INVALID_HANDLE_VALUE; 441 } 399 442 400 443 if (!CloseHandle(pWorker->OverlappedRead.hEvent)) … … 421 464 int rc; 422 465 423 if (close(pWorker->fdSocket) != 0) 424 warn("close(pWorker->fdSocket)"); 425 pWorker->fdSocket = -1; 466 if (pWorker->fdSocket != -1) 467 { 468 if (close(pWorker->fdSocket) != 0) 469 warn("close(pWorker->fdSocket)"); 470 pWorker->fdSocket = -1; 471 } 426 472 427 473 kill(pWorker->pid, SIGTERM); … … 434 480 * Unlink it from the hash table. 435 481 */ 436 idxHash = KWORKER_PID_HASH(pWorker->pid); 437 if (g_apPidHash[idxHash] == pWorker) 438 g_apPidHash[idxHash] = pWorker->pNext; 439 else 440 { 441 PWORKERINSTANCE pPrev = g_apPidHash[idxHash]; 442 while (pPrev && pPrev->pNext != pWorker) 443 pPrev = pPrev->pNext; 444 assert(pPrev != NULL); 445 if (pPrev) 446 pPrev->pNext = pWorker->pNext; 447 } 448 pWorker->pid = -1; 482 kSubmitPidHashRemove(pWorker); 449 483 450 484 /* … … 598 632 * @param pvMsg The message to send. 599 633 * @param cbMsg The size of the message. 634 * @param fNoRespawning Set if 600 635 * @param cVerbosity The verbosity level. 601 636 */ 602 static int kSubmitSendJobMessage(PWORKERINSTANCE pWorker, void const *pvMsg, uint32_t cbMsg, int cVerbosity) 603 { 604 int cRetries = 1; 605 for (;; cRetries--) 637 static int kSubmitSendJobMessage(PWORKERINSTANCE pWorker, void const *pvMsg, uint32_t cbMsg, int fNoRespawning, int cVerbosity) 638 { 639 int cRetries; 640 641 /* 642 * Respawn the worker if it stopped by itself and we closed the pipe already. 643 */ 644 #ifdef KBUILD_OS_WINDOWS 645 if (pWorker->hPipe == INVALID_HANDLE_VALUE) 646 #else 647 if (pWorker->fdSocket == -1) 648 #endif 649 { 650 if (!fNoRespawning) 651 { 652 if (cVerbosity > 0) 653 fprintf(stderr, "kSubmit: Respawning worker (#1)...\n"); 654 if (kSubmitRespawnWorker(pWorker, cVerbosity) != 0) 655 return 2; 656 } 657 658 } 659 660 /* 661 * Restart-on-broken-pipe loop. Necessary? 662 */ 663 for (cRetries = !fNoRespawning ? 1 : 0; ; cRetries--) 606 664 { 607 665 /* … … 650 708 * Broken connection. Try respawn the worker. 651 709 */ 710 if (cVerbosity > 0) 711 fprintf(stderr, "kSubmit: Respawning worker (#2)...\n"); 652 712 if (kSubmitRespawnWorker(pWorker, cVerbosity) != 0) 653 713 return 2; 654 714 } 655 715 } 716 717 718 /** 719 * Closes the connection on a worker that said it is going to exit now. 720 * 721 * This is a way of dealing with imperfect resource management in the worker, it 722 * will monitor it a little and trigger a respawn when it looks bad. 723 * 724 * This function just closes the pipe / socket connection to the worker. The 725 * kSubmitSendJobMessage function will see this a trigger a respawn the next 726 * time the worker is engaged. This will usually mean there's a little delay in 727 * which the process can terminate without us having to actively wait for it. 728 * 729 * @param pWorker The worker instance. 730 */ 731 static void kSubmitCloseConnectOnExitingWorker(PWORKERINSTANCE pWorker) 732 { 733 #ifdef KBUILD_OS_WINDOWS 734 if (!CloseHandle(pWorker->hPipe)) 735 warnx("CloseHandle(pWorker->hPipe): %u", GetLastError()); 736 pWorker->hPipe = INVALID_HANDLE_VALUE; 737 #else 738 if (close(pWorker->fdSocket) != 0) 739 warn("close(pWorker->fdSocket)"); 740 pWorker->fdSocket = -1; 741 #endif 742 } 743 744 745 #ifdef KBUILD_OS_WINDOWS 746 747 /** 748 * Handles read failure. 749 * 750 * @returns Exit code. 751 * @param pWorker The worker instance. 752 * @param dwErr The error code. 753 */ 754 static int kSubmitWinReadFailed(PWORKERINSTANCE pWorker, DWORD dwErr) 755 { 756 DWORD dwExitCode; 757 758 if (pWorker->cbResultRead == 0) 759 errx(1, "ReadFile failed: %u", dwErr); 760 else 761 errx(1, "ReadFile failed: %u (read %u bytes)", dwErr, pWorker->cbResultRead); 762 assert(dwErr != 0); 763 764 /* Complete the result. */ 765 pWorker->Result.s.rcExit = 127; 766 pWorker->Result.s.bWorkerExiting = 1; 767 pWorker->cbResultRead = sizeof(pWorker->Result); 768 769 if (GetExitCodeProcess(pWorker->hProcess, &dwExitCode)) 770 { 771 if (dwExitCode != 0) 772 pWorker->Result.s.rcExit = dwExitCode; 773 } 774 775 return dwErr != 0 ? (int)(dwErr & 0x7fffffff) : 0x7fffffff; 776 777 } 778 779 780 /** 781 * Used by 782 * @returns 0 if we got the whole result, -1 if I/O is pending, windows last 783 * error on ReadFile failure. 784 * @param pWorker The worker instance. 785 */ 786 static int kSubmitReadMoreResultWin(PWORKERINSTANCE pWorker) 787 { 788 /* 789 * Set up the result read, telling the sub_proc.c unit about it. 790 */ 791 while (pWorker->cbResultRead < sizeof(pWorker->Result)) 792 { 793 DWORD cbRead = 0; 794 795 BOOL fRc = ResetEvent(pWorker->OverlappedRead.hEvent); 796 assert(fRc); (void)fRc; 797 798 pWorker->OverlappedRead.Offset = 0; 799 pWorker->OverlappedRead.OffsetHigh = 0; 800 801 if (!ReadFile(pWorker->hPipe, &pWorker->Result.ab[pWorker->cbResultRead], 802 sizeof(pWorker->Result) - pWorker->cbResultRead, 803 &cbRead, 804 &pWorker->OverlappedRead)) 805 { 806 DWORD dwErr = GetLastError(); 807 if (dwErr == ERROR_IO_PENDING) 808 return 1; 809 return kSubmitWinReadFailed(pWorker, GetLastError()); 810 } 811 812 pWorker->cbResultRead += cbRead; 813 assert(pWorker->cbResultRead <= sizeof(pWorker->Result)); 814 } 815 return 0; 816 } 817 818 #endif /* KBUILD_OS_WINDOWS */ 819 820 /** 821 * Marks the worker active. 822 * 823 * On windows this involves setting up the async result read and telling 824 * sub_proc.c about the process. 825 * 826 * @returns Exit code. 827 * @param pWorker The worker instance to mark as active. 828 * @param cVerbosity The verbosity level. 829 * @param pChild The kmk child to associate the job with. 830 * @param pPidSpawned If @a *pPidSpawned is non-zero if the child is 831 * running, otherwise the worker is already done 832 * and we've returned the exit code of the job. 833 */ 834 static int kSubmitMarkActive(PWORKERINSTANCE pWorker, int cVerbosity, struct child *pChild, pid_t *pPidSpawned) 835 { 836 #ifdef KBUILD_OS_WINDOWS 837 int rc; 838 #endif 839 840 pWorker->cbResultRead = 0; 841 842 #ifdef KBUILD_OS_WINDOWS 843 /* 844 * Setup the async result read on windows. If we're slow and the worker 845 * very fast, this may actually get the result immediately. 846 */ 847 l_again: 848 rc = kSubmitReadMoreResultWin(pWorker); 849 if (rc == -1) 850 { 851 if (process_kmk_register_submit(pWorker->OverlappedRead.hEvent, (intptr_t)pWorker) == 0) 852 { /* likely */ } 853 else 854 { 855 /* We need to do the waiting here because sub_proc.c has too much to do. */ 856 warnx("Too many processes for sub_proc.c to handle!"); 857 WaitForSingleObject(pWorker->OverlappedRead.hEvent, INFINITE); 858 goto l_again; 859 } 860 } 861 else 862 { 863 assert(rc == 0 || pWorker->Result.s.rcExit != 0); 864 if (pWorker->Result.s.bWorkerExiting) 865 kSubmitCloseConnectOnExitingWorker(pWorker); 866 *pPidSpawned = 0; 867 return pWorker->Result.s.rcExit; 868 } 869 #endif 870 871 /* 872 * Mark it busy and move it to the active instance. 873 */ 874 pWorker->pBusyWith = pChild; 875 *pPidSpawned = pWorker->pid; 876 877 kSubmitListUnlink(&g_IdleList, pWorker); 878 kSubmitListAppend(&g_BusyList, pWorker); 879 return 0; 880 } 881 882 883 #ifdef KBUILD_OS_WINDOWS 884 885 /** 886 * Retrieve the worker child result. 887 * 888 * If incomplete, we restart the ReadFile operation like kSubmitMarkActive does. 889 * 890 * @returns 0 on success, -1 if ReadFile was restarted. 891 * @param pvUser The worker instance. 892 * @param prcExit Where to return the exit code. 893 * @param piSigNo Where to return the signal number. 894 */ 895 int kSubmitSubProcGetResult(intptr_t pvUser, int *prcExit, int *piSigNo) 896 { 897 PWORKERINSTANCE pWorker = (PWORKERINSTANCE)pvUser; 898 899 /* 900 * Get the overlapped result. There should be one since we're here 901 * because of a satisfied WaitForMultipleObject. 902 */ 903 DWORD cbRead = 0; 904 if (GetOverlappedResult(pWorker->hPipe, &pWorker->OverlappedRead, &cbRead, TRUE)) 905 { 906 pWorker->cbResultRead += cbRead; 907 assert(pWorker->cbResultRead <= sizeof(pWorker->Result)); 908 909 /* More to be read? */ 910 while (pWorker->cbResultRead < sizeof(pWorker->Result)) 911 { 912 int rc = kSubmitReadMoreResultWin(pWorker); 913 if (rc == -1) 914 return -1; 915 assert(rc == 0 || pWorker->Result.s.rcExit != 0); 916 } 917 assert(pWorker->cbResultRead == sizeof(pWorker->Result)); 918 } 919 else 920 { 921 DWORD dwErr = GetLastError(); 922 kSubmitWinReadFailed(pWorker, dwErr); 923 } 924 925 /* 926 * Okay, we've got a result. 927 */ 928 *prcExit = pWorker->Result.s.rcExit; 929 switch (pWorker->Result.s.rcExit) 930 { 931 default: *piSigNo = 0; break; 932 case CONTROL_C_EXIT: *piSigNo = SIGINT; break; 933 case STATUS_INTEGER_DIVIDE_BY_ZERO: *piSigNo = SIGFPE; break; 934 case STATUS_ACCESS_VIOLATION: *piSigNo = SIGSEGV; break; 935 case STATUS_PRIVILEGED_INSTRUCTION: 936 case STATUS_ILLEGAL_INSTRUCTION: *piSigNo = SIGILL; break; 937 } 938 return 0; 939 } 940 941 942 int kSubmitSubProcKill(intptr_t pvUser, int iSignal) 943 { 944 return -1; 945 } 946 947 #endif /* KBUILD_OS_WINDOWS */ 948 949 950 /** 951 * atexit callback that trigger worker termination. 952 */ 953 static void kSubmitAtExitCallback(void) 954 { 955 PWORKERINSTANCE pWorker; 956 DWORD msStartTick; 957 DWORD cKillRaids = 0; 958 959 /* 960 * Tell all the workers to exit by breaking the connection. 961 */ 962 for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext) 963 kSubmitCloseConnectOnExitingWorker(pWorker); 964 for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext) 965 kSubmitCloseConnectOnExitingWorker(pWorker); 966 967 /* 968 * Wait a little while for them to stop. 969 */ 970 Sleep(0); 971 msStartTick = GetTickCount(); 972 for (;;) 973 { 974 /* 975 * Collect handles of running processes. 976 */ 977 PWORKERINSTANCE apWorkers[MAXIMUM_WAIT_OBJECTS]; 978 HANDLE ahHandles[MAXIMUM_WAIT_OBJECTS]; 979 DWORD cHandles; 980 981 for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext) 982 if (pWorker->hProcess != INVALID_HANDLE_VALUE) 983 { 984 if (cHandles < MAXIMUM_WAIT_OBJECTS) 985 { 986 apWorkers[cHandles] = pWorker; 987 ahHandles[cHandles] = pWorker->hProcess; 988 } 989 cHandles++; 990 } 991 for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext) 992 if (pWorker->hProcess != INVALID_HANDLE_VALUE) 993 { 994 if (cHandles < MAXIMUM_WAIT_OBJECTS) 995 { 996 apWorkers[cHandles] = pWorker; 997 ahHandles[cHandles] = pWorker->hProcess; 998 } 999 cHandles++; 1000 } 1001 if (cHandles == 0) 1002 return; 1003 1004 /* 1005 * Wait for the processes. 1006 */ 1007 for (;;) 1008 { 1009 DWORD cMsElapsed = GetTickCount() - msStartTick; 1010 DWORD dwWait = WaitForMultipleObjects(cHandles <= MAXIMUM_WAIT_OBJECTS ? cHandles : MAXIMUM_WAIT_OBJECTS, 1011 ahHandles, FALSE /*bWaitAll*/, 1012 cMsElapsed < 1000 ? 1000 - cMsElapsed + 16 : 16); 1013 if ( dwWait >= WAIT_OBJECT_0 1014 && dwWait <= WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS) 1015 { 1016 size_t idx = dwWait - WAIT_OBJECT_0; 1017 CloseHandle(apWorkers[idx]->hProcess); 1018 apWorkers[idx]->hProcess = INVALID_HANDLE_VALUE; 1019 1020 if (cHandles <= MAXIMUM_WAIT_OBJECTS) 1021 { 1022 /* Restart the wait with the worker removed, or quit if it was the last worker. */ 1023 cHandles--; 1024 if (!cHandles) 1025 return; 1026 if (idx != cHandles) 1027 { 1028 apWorkers[idx] = apWorkers[cHandles]; 1029 ahHandles[idx] = ahHandles[cHandles]; 1030 } 1031 continue; 1032 } 1033 /* else: Reconstruct the wait array so we get maximum coverage. */ 1034 } 1035 else if (dwWait == WAIT_TIMEOUT) 1036 { 1037 /* Terminate the whole bunch. */ 1038 cKillRaids++; 1039 if (cKillRaids <= 2) 1040 { 1041 fprintf(stderr, "kmk/kSubmit: Killing %u lingering worker processe(s)!\n", cHandles); 1042 for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext) 1043 if (pWorker->hProcess != INVALID_HANDLE_VALUE) 1044 TerminateProcess(pWorker->hProcess, WAIT_TIMEOUT); 1045 for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext) 1046 if (pWorker->hProcess != INVALID_HANDLE_VALUE) 1047 TerminateProcess(pWorker->hProcess, WAIT_TIMEOUT); 1048 } 1049 else 1050 { 1051 fprintf(stderr, "kmk/kSubmit: Giving up on the last %u worker processe(s). :-(\n", cHandles); 1052 break; 1053 } 1054 } 1055 else 1056 { 1057 /* Some kind of wait error. Could be a bad handle, check each and remove 1058 bad ones as well as completed ones. */ 1059 size_t idx; 1060 fprintf(stderr, "kmk/kSubmit: WaitForMultipleObjects unexpectedly returned %#u (err=%u)\n", 1061 dwWait, GetLastError()); 1062 for (idx = 0; idx < cHandles; idx++) 1063 { 1064 dwWait = WaitForSingleObject(ahHandles[idx], 0 /*ms*/); 1065 if (dwWait != WAIT_TIMEOUT) 1066 { 1067 CloseHandle(apWorkers[idx]->hProcess); 1068 apWorkers[idx]->hProcess = INVALID_HANDLE_VALUE; 1069 } 1070 } 1071 } 1072 break; 1073 } /* wait loop */ 1074 } /* outer wait loop */ 1075 } 1076 656 1077 657 1078 … … 881 1302 882 1303 883 int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild )1304 int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned) 884 1305 { 885 1306 int rcExit = 0; … … 1053 1474 1054 1475 case 'V': 1055 printf("kmk_submit - kBuild version %d.%d.%d (r%u)\n" 1056 "Copyright (C) 2007-2016 knut st. osmundsen\n", 1057 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, 1058 KBUILD_SVN_REV); 1059 return 0; 1476 return kbuild_version(argv[0]); 1060 1477 } 1061 1478 } while ((chOpt = *pszArg++) != '\0'); … … 1078 1495 if (pWorker) 1079 1496 { 1080 rcExit = kSubmitSendJobMessage(pWorker, pvMsg, cbMsg, cVerbosity);1497 rcExit = kSubmitSendJobMessage(pWorker, pvMsg, cbMsg, 0 /*fNoRespawning*/, cVerbosity); 1081 1498 if (rcExit == 0) 1082 { 1083 pWorker->pBusyWith = pChild; 1084 /** @todo integrate with sub_proc.c / whatever. */ 1085 } 1499 rcExit = kSubmitMarkActive(pWorker, cVerbosity, pChild, pPidSpawned); 1500 1501 if (!g_fAtExitRegistered) 1502 if (atexit(kSubmitAtExitCallback) == 0) 1503 g_fAtExitRegistered = 1; 1086 1504 } 1087 1505 else -
trunk/src/kmk/w32/include/sub_proc.h
r2591 r2843 39 39 EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data, 40 40 int stdin_data_len)); 41 #ifndef KMK /* unused */ 41 42 EXTERN_DECL(long process_file_io, (HANDLE proc)); 43 #endif 42 44 EXTERN_DECL(void process_cleanup, (HANDLE proc)); 43 45 EXTERN_DECL(HANDLE process_wait_for_any, (VOID_DECL)); … … 46 48 EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal)); 47 49 EXTERN_DECL(int process_used_slots, (VOID_DECL)); 50 #ifdef KMK 51 EXTERN_DECL(int process_kmk_register_submit, (HANDLE hEvent, intptr_t clue)); 52 #endif 48 53 49 54 /* support routines */ -
trunk/src/kmk/w32/subproc/sub_proc.c
r2636 r2843 27 27 #include <signal.h> 28 28 #include <windows.h> 29 #ifdef KMK 30 # include <assert.h> 31 # include "make.h" 32 # include "kmkbuiltin.h" 33 #endif 34 29 35 30 36 #include "sub_proc.h" … … 34 40 35 41 static char *make_command_line(char *shell_name, char *exec_path, char **argv); 42 #ifndef KMK 36 43 extern char *xmalloc (unsigned int); 37 # ifdef KMK44 #else 38 45 extern void kmk_cache_exec_image(const char *); /* imagecache.c */ 39 46 #endif 40 47 41 48 typedef struct sub_process_t { 49 #ifdef KMK 50 enum { kRegular = 0, kSubmit, kSubProcFreed } enmType; 51 intptr_t clue; 52 #endif 42 53 intptr_t sv_stdin[2]; 43 54 intptr_t sv_stdout[2]; … … 64 75 static int fake_exits_pending = 0; 65 76 77 #ifndef KMK /* Inefficient! */ 66 78 /* 67 79 * When a process has been waited for, adjust the wait state … … 88 100 } 89 101 } 102 #endif /* !KMK */ 90 103 91 104 /* … … 112 125 /* wait for someone to exit */ 113 126 if (!fake_exits_pending) { 127 #ifdef KMK 128 l_wait_again: 129 #endif 114 130 retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE); 115 131 which = retval - WAIT_OBJECT_0; … … 123 139 if (retval != WAIT_FAILED) { 124 140 sub_process* pproc = proc_array[which]; 141 #ifdef KMK 142 if (pproc->enmType == kSubmit) { 143 /* Try get the result from kSubmit.c. This may not succeed if the whole 144 result hasn't arrived yet, in which we just restart the wait. */ 145 if (kSubmitSubProcGetResult(pproc->clue, &pproc->exit_code, &pproc->signal) != 0) { 146 goto l_wait_again; 147 } 148 } 149 #endif 150 #ifndef KMK /* Inefficient! */ 125 151 process_adjust_wait_state(pproc); 152 #else 153 proc_index--; 154 if ((int)which < proc_index) 155 proc_array[which] = proc_array[proc_index]; 156 proc_array[proc_index] = NULL; 157 #endif 126 158 return pproc; 127 159 } else … … 133 165 */ 134 166 BOOL 135 process_kill(HANDLE proc, int signal)167 process_kill(HANDLE proc, int signal) 136 168 { 137 169 sub_process* pproc = (sub_process*) proc; 138 170 pproc->signal = signal; 171 #ifdef KMK 172 if (pproc->enmType == kRegular) { 173 #endif 139 174 return (TerminateProcess((HANDLE) pproc->pid, signal)); 175 #ifdef KMK 176 } else if (pproc->enmType == kSubmit) { 177 return kSubmitSubProcKill(pproc->clue, signal) == 0; 178 } 179 assert(0); 180 return FALSE; 181 #endif 140 182 } 141 183 … … 149 191 process_register(HANDLE proc) 150 192 { 193 #ifdef KMK 194 assert(((sub_process *)proc)->enmType == kRegular); 195 #endif 151 196 if (proc_index < MAXIMUM_WAIT_OBJECTS) 152 197 proc_array[proc_index++] = (sub_process *) proc; 153 198 } 199 200 #ifdef KMK 201 /** 202 * Interface used by kmkbuiltin/kSubmit.c to register stuff going down in a 203 * worker process. 204 * 205 * @returns 0 on success, -1 if there are too many sub-processes already. 206 * @param hEvent The event semaphore to wait on. 207 * @param clue The clue to base. 208 */ 209 int 210 process_kmk_register_submit(HANDLE hEvent, intptr_t clue) 211 { 212 if (proc_index < MAXIMUM_WAIT_OBJECTS) { 213 sub_process *pSubProc = (sub_process *)xcalloc(sizeof(*pSubProc)); 214 pSubProc->enmType = kSubmit; 215 pSubProc->clue = clue; 216 pSubProc->pid = (intptr_t)hEvent; 217 218 proc_array[proc_index++] = pSubProc; 219 return 0; 220 } 221 return -1; 222 } 223 #endif 154 224 155 225 /* … … 197 267 */ 198 268 #ifdef KMK 199 (void) process_file_io_private(pproc, FALSE); 269 if (pproc->enmType == kRegular) { 270 (void)process_file_io_private(pproc, FALSE); 271 } 200 272 #else 201 273 (void) process_file_io(pproc); … … 445 517 #ifdef KMK 446 518 size_t exec_path_len; 519 520 assert (pproc->enmType == kRegular); 447 521 #endif 448 522 … … 783 857 bool_t child_dead = FALSE; 784 858 BOOL GetExitCodeResult; 859 #ifdef KMK 860 assert (pproc->enmType == kRegular); 861 #endif 785 862 786 863 /* … … 918 995 } 919 996 997 #ifndef KMK /* unused */ 920 998 /* 921 999 * Purpose: collects output from child process and returns results … … 943 1021 return process_file_io_private(proc, TRUE); 944 1022 } 1023 #endif /* !KMK - unused */ 945 1024 946 1025 /* private function, avoid some kernel calls. (bird) */ … … 1024 1103 int i; 1025 1104 1105 #ifdef KMK 1106 if (pproc->enmType == kRegular) { 1107 #endif 1108 1026 1109 if (pproc->using_pipes) { 1027 1110 for (i= 0; i <= 1; i++) { … … 1036 1119 if ((HANDLE)pproc->pid) 1037 1120 CloseHandle((HANDLE)pproc->pid); 1121 #ifdef KMK 1122 } else if (pproc->enmType == kSubmit) { 1123 /* nothing to do. */ 1124 } else { 1125 assert(0); 1126 return; 1127 } 1128 pproc->enmType = kSubProcFreed; 1129 #endif 1038 1130 1039 1131 free(pproc);
Note:
See TracChangeset
for help on using the changeset viewer.