BOOL CPrime95App::InitInstance() { int orig_cmdShow; int named_ini_files = -1; int torture_test = 0; char *p; // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. //SetRegistryKey(_T("GIMPS")); //LoadStdProfileSettings(0); // Load standard INI file options (including MRU) // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_MDITYPE, RUNTIME_CLASS(CPrime95Doc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CPrime95View)); if (!pDocTemplate) return FALSE; AddDocTemplate(pDocTemplate); // Init our view mutexes gwmutex_init (&VIEW_MUTEX); gwmutex_init (&VIEW_LINES_MUTEX); // create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) { delete pMainFrame; return FALSE; } m_pMainWnd = pMainFrame; // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // Dispatch commands specified on the command line orig_cmdShow = m_nCmdShow; if (!ProcessShellCommand(cmdInfo)) return FALSE; /* Change the working directory to the same directory that */ /* the executable is located. This is especially important */ /* for running prime95 as a Windows 95 service */ { char buf[256]; GetModuleFileName (NULL, buf, sizeof (buf)); strrchr (buf, '\\')[1] = 0; _chdir (buf); } /* Initialize gwnum call back routines. Using callback routines lets the */ /* gwnum library have a nice clean interface for users that do not need */ /* additional functionality that only prime95 uses. */ StopCheckRoutine = stopCheck; OutputBothRoutine = OutputBoth; /* NT services are not passed command line arguments. In this case we */ /* encode the -An information in the NT service name. */ if (NTSERVICENAME[0] && NTSERVICENAME[15] == '-') named_ini_files = atoi (&NTSERVICENAME[16]); // Process command line switches for (p = m_lpCmdLine; *p == '//' || *p == '-'; ) { p++; switch (*p++) { // Accept a -A switch indicating an alternate set of INI files // are to be used. case 'A': case 'a': named_ini_files = 0; while (isspace (*p)) p++; while (isdigit (*p)) { named_ini_files = named_ini_files * 10 + (*p - '0'); p++; } break; // Accept a -T switch to run the torture test. case 'T': case 't': torture_test = 1; break; // Accept a -W switch indicating an alternate working directory. case 'W': case 'w': { char buf[256]; char *bufp = buf; while (isspace (*p)) p++; while (*p && !isspace (*p)) *bufp++ = *p++; *bufp = 0; _chdir (buf); } break; } // Skip whitespace between switches while (isspace (*p)) p++; } // Make sure only one copy of prime95 is running at a time. // This code is courtesy of Jeroen C. van Gelderen // I enhanced it to allow multiple copies if they are running // from different directories or use different -A switches. { char buf[256]; char *p; DWORD mutex_error_code; PSID pEveryoneSID = NULL, pAdminSID = NULL; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea[1]; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SECURITY_ATTRIBUTES sa; // Turn directory name into a (likely) unique integer // Add in the -A value. Use this integer to create a mutex name. _getcwd (buf, 255); for (p = buf; *p; p++) g_MutexNum = g_MutexNum * 17 + *p; g_MutexNum += named_ini_files; sprintf (buf, "Global\\GIMPS%ld", g_MutexNum); /* Create a world access security descriptor to share the Mutex we */ /* are about to create. If we run into any troubles, assume this is */ /* a Windows 95/98/Me system and create a simple Mutex. */ // Create a well-known SID for the Everyone group. if (! AllocateAndInitializeSid ( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID)) goto simple_mutex; // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the Administrators group full access to the key. ZeroMemory (&ea, sizeof (EXPLICIT_ACCESS)); ea[0].grfAccessPermissions = EVENT_ALL_ACCESS; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance= NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; // Create a new ACL that contains the new ACEs. if (SetEntriesInAcl (1, ea, NULL, &pACL) != ERROR_SUCCESS) goto simple_mutex; // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == NULL) goto simple_mutex; if (! InitializeSecurityDescriptor (pSD, SECURITY_DESCRIPTOR_REVISION)) goto simple_mutex; // Add the ACL to the security descriptor. if (! SetSecurityDescriptorDacl (pSD, TRUE, pACL, FALSE)) goto simple_mutex; // Initialize a security attributes structure. sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; // Create our mutex. Windows XP uses terminal services to support user // switching. The "Global\" prefix is required so that this mutex is // is created in the global kernel objects namespace. Unfortunately, // the "\" character raises an error on Windows 95/98/Me systems. g_hMutexInst = CreateMutex ( &sa, // World access FALSE, // Not owned !! buf); // Unique name if (g_hMutexInst == NULL) simple_mutex: g_hMutexInst = CreateMutex ( NULL, // No security stuff FALSE, // Not owned !! buf+7); // Unique name mutex_error_code = GetLastError (); // Cleanup all the security structures we initialized if (pEveryoneSID) FreeSid (pEveryoneSID); if (pACL) LocalFree (pACL); if (pSD) LocalFree (pSD); // Test for failure if (g_hMutexInst == NULL) return 0; // If mutex already exists then another instance is already running if (mutex_error_code == ERROR_ALREADY_EXISTS) { HWND hwndPrevInst = 0; // Give other instance a little time to display it's main window Sleep (750); // Find the window handle EnumWindows (&MyEnumProc, (LPARAM) &hwndPrevInst); // Unhide the other instance's window if (hwndPrevInst) { ShowWindow (hwndPrevInst, SW_HIDE); ShowWindow (hwndPrevInst, SW_SHOWMINIMIZED); ShowWindow (hwndPrevInst, SW_SHOWNORMAL); } CloseHandle (g_hMutexInst); g_hMutexInst = NULL; return 0; } // Set the window user data so we can be identified by // another instance of this program. SetWindowLongPtr (m_pMainWnd->m_hWnd, GWLP_USERDATA, (LONG_PTR) g_MutexNum); } /* Cache icon handles to work around Windows deadlocking bug */ ICON_IDLE = LoadIcon (IDI_YELLOW_ICON); ICON_WORKING = LoadIcon (IDR_MAINFRAME); /* Name and read the INI files. Perform some other startup initializations. */ nameAndReadIniFiles (named_ini_files); initCommCode (); /* Before processing the INI file, hide and/or position the */ /* main window so that we can display error messages */ m_pMainWnd->SetWindowText ("Prime95"); WINDOWPLACEMENT wp; m_pMainWnd->GetWindowPlacement (&wp); int left = IniGetInt (INI_FILE, "Left", 0); int top = IniGetInt (INI_FILE, "Top", 0); int right = IniGetInt (INI_FILE, "Right", 0); int bottom = IniGetInt (INI_FILE, "Bottom", 0); if (right + left + top + bottom != 0) { wp.rcNormalPosition.left = left; wp.rcNormalPosition.top = top; wp.rcNormalPosition.right = right; wp.rcNormalPosition.bottom = bottom; } wp.showCmd = HIDE_ICON ? SW_HIDE : SW_SHOWMINIMIZED; m_pMainWnd->SetWindowPlacement (&wp); /* Now show the main window and post initial messages */ // Put prime95 in the system tray if (TRAY_ICON) TrayMessage (NIM_ADD, "Prime95", 0); // See if we are running as a Windows95 service WINDOWS95_SERVICE = IniGetInt (INI_FILE, "Windows95Service", 0); WINDOWS95_A_SWITCH = named_ini_files; Service95 (); // Run the torture test if asked to by a command line argument if (torture_test) { m_pMainWnd->ShowWindow (orig_cmdShow); m_pMainWnd->PostMessage (WM_COMMAND, USR_TORTURE, 0); } // On first run, see if this is a stress tester. If not, step // user throught the primenet dialog boxes. else if (STRESS_TESTER == 99) { m_pMainWnd->ShowWindow (orig_cmdShow); m_pMainWnd->PostMessage (WM_COMMAND, USR_WELCOME, 0); } // Take stress testers straight to the torture dialog box else if (STRESS_TESTER) { m_pMainWnd->ShowWindow (orig_cmdShow); m_pMainWnd->PostMessage (WM_COMMAND, IDM_TORTURE, 0); } // Auto-continue if there is any work to do. else if (USE_PRIMENET || WELL_BEHAVED_WORK || WORKTODO_COUNT) { m_pMainWnd->PostMessage (WM_COMMAND, IDM_CONTINUE, 0); } // Otherwise, show the window else if (!HIDE_ICON) { m_pMainWnd->ShowWindow (orig_cmdShow); ChangeIcon (MAIN_THREAD_NUM, IDLE_ICON); } // Initialization complete return TRUE; }
int main ( int argc, char *argv[]) { char buf[256]; int named_ini_files = -1; int contact_server = 0; int torture_test = 0; int i, nice_level; char *p; /* catch termination signals */ (void)signal(SIGTERM, sigterm_handler); (void)signal(SIGINT, sigterm_handler); /* No buffering of output */ setvbuf (stdout, NULL, _IONBF, 0); /* Change to the executable's directory */ /* NOTE: This only changes the working directory if the user typed */ /* in a full path to the executable (as opposed to finding it on the PATH) */ strcpy (buf, argv[0]); p = strrchr (buf, '/'); if (p != NULL) { *p = 0; (void) _chdir (buf); } /* Initialize gwnum call back routines. Using callback routines lets the */ /* gwnum library have a nice clean interface for users that do not need */ /* additional functionality that only prime95 uses. */ StopCheckRoutine = stopCheck; OutputBothRoutine = OutputBoth; /* Process command line switches */ for (i = 1; i < argc; i++) { p = argv[i]; if (*p++ != '-') break; switch (*p++) { /* Accept a -A switch indicating an alternate set of INI files */ /* are to be used. */ case 'A': case 'a': named_ini_files = 0; while (isspace (*p)) p++; while (isdigit (*p)) { named_ini_files = named_ini_files * 10 + (*p - '0'); p++; } break; /* -C - contact the server now, then exit */ case 'C': case 'c': contact_server = 1; VERBOSE = TRUE; NO_GUI = FALSE; break; /* -D - debug */ case 'D': case 'd': VERBOSE = TRUE; NO_GUI = FALSE; break; /* -H - help */ case 'H': case 'h': case '?': goto usage; /* -M - Menu */ case 'M': case 'm': MENUING = 1; NO_GUI = FALSE; break; /* -S - status */ case 'S': case 's': MENUING = 2; NO_GUI = FALSE; break; /* -T - Torture test */ case 'T': case 't': torture_test = TRUE; break; /* -V - version number */ case 'V': case 'v': printf ("Mersenne Prime Test Program, Version %s.%d\n", VERSION, PORT); return (0); /* -W - use a different working directory */ case 'W': case 'w': (void) _chdir (p); break; /* Otherwise unknown switch */ default: printf ("Invalid switch\n"); goto usage; } } /* Determine the names of the INI files, read them, do other initialization. */ /* Skip the comm code initialization if we are just displaying the status */ /* or running a torture test */ nameAndReadIniFiles (named_ini_files); if (MENUING != 2 && !torture_test) initCommCode (); /* If not running a torture test, set the program to nice priority. */ /* Technically, this is not necessary since worker threads are set to */ /* the lowest possible priority. However, sysadmins might be alarmed */ /* to see a CPU intensive program not running at nice priority when */ /* executing a ps command. */ #if defined (__linux__) || defined (__APPLE__) || defined (__FreeBSD__) /* Linux/FreeBSD ranges from -20 to +19, lower values give more favorable scheduling */ nice_level = IniGetInt (INI_FILE, "Nice", 10); if (!torture_test && nice_level) { setpriority (PRIO_PROCESS, 0, nice_level); } #endif /* If running the torture test, do so now. */ if (torture_test) { int num_threads; VERBOSE = TRUE; NO_GUI = FALSE; num_threads = IniGetInt (INI_FILE, "TortureThreads", NUM_CPUS * CPU_HYPERTHREADS); LaunchTortureTest (num_threads, TRUE); } /* If this is a stress tester, then turn on menuing. */ else if (IniGetInt (INI_FILE, "StressTester", 99) == 1) { MENUING = 1; VERBOSE = TRUE; NO_GUI = FALSE; main_menu (); } /* On first run, get user id before contacting server */ /* for a work assignment. To make first time user more comfortable, we will */ /* display data to the screen, rather than running silently. */ else if (IniGetInt (INI_FILE, "StressTester", 99) == 99) { VERBOSE = TRUE; NO_GUI = FALSE; test_welcome (); } /* If we are to contact the server, do so now. This option lets the */ /* user create a batch file that contacts the server at regular intervals */ /* or when the ISP is contacted, etc. */ else if (contact_server) { do_manual_comm_now (); while (COMMUNICATION_THREAD) Sleep (50); } /* Bring up the main menu */ else if (MENUING == 1) main_menu (); else if (MENUING == 2) test_status(); /* Continue testing, return when worker threads exit. */ else { linuxContinue ("Another mprime is already running!\n", ALL_WORKERS, TRUE); } /* Write the worktodo file in case the WELL_BEHAVED_WORK flag caused us */ /* to delay writing the file. */ writeWorkToDoFile (TRUE); /* All done */ return (0); /* Invalid args message */ usage: printf ("Usage: mprime [-cdhmstv] [-aN] [-wDIR]\n"); printf ("-c\tContact the PrimeNet server, then exit.\n"); printf ("-d\tPrint detailed information to stdout.\n"); printf ("-h\tPrint this.\n"); printf ("-m\tMenu to configure mprime.\n"); printf ("-s\tDisplay status.\n"); printf ("-t\tRun the torture test.\n"); printf ("-v\tPrint the version number.\n"); printf ("-aN\tUse an alternate set of INI and output files (obsolete).\n"); printf ("-wDIR\tRun from a different working directory.\n"); printf ("\n"); return (1); }