- /* 
-     Protector -- a UCI chess engine 
-   
-     Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com) 
-   
-     This program 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. 
-   
-     This program 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 "coordination.h" 
- #include "protector.h" 
- #include "search.h" 
- #include "matesearch.h" 
- #include "io.h" 
- #include "hash.h" 
- #include <stdio.h> 
- #include <assert.h> 
- #ifndef _MSC_VER 
- #include <pthread.h> 
- #else // _MSC_VER 
- #include <process.h> // Pierre-Marie Baty -- Win32 threads support 
- __declspec(dllimport) void __stdcall Sleep (unsigned long Timeout); // Pierre-Marie Baty -- for Sleep() 
- #endif // !_MSC_VER 
- #include <time.h> 
-   
- /* #define DEBUG_COORDINATION */ 
-   
- #ifndef _MSC_VER 
- #define THREAD_RETURN_TYPE void * // Pierre-Marie Baty -- multiplatform threads support 
- #define INVALID_THREAD_ID 0 // Pierre-Marie Baty -- multiplatform threads support 
- pthread_t searchThread[MAX_THREADS]; 
- pthread_t timer; 
- static pthread_mutex_t guiSearchMutex = PTHREAD_MUTEX_INITIALIZER; 
- #else // _MSC_VER 
- #define THREAD_RETURN_TYPE unsigned int // Pierre-Marie Baty -- Win32 threads support 
- #define INVALID_THREAD_ID -1 // Pierre-Marie Baty -- Win32 threads support 
- uintptr_t searchThread[MAX_THREADS]; // Pierre-Marie Baty -- Win32 threads support 
- uintptr_t timer; // Pierre-Marie Baty -- Win32 threads support 
- static bool guiSearchMutex = false; // Pierre-Marie Baty -- Win32 threads support 
- bool terminate_timer = false; // Pierre-Marie Baty -- Win32 threads support 
- #endif // !_MSC_VER 
- long searchThreadId[MAX_THREADS]; 
-   
- static int numThreads = 1; 
- static SearchTask dummyTask; 
- static SearchTask *currentTask = &dummyTask; 
- static Variation variations[MAX_THREADS]; 
- static Hashtable sharedHashtable; 
- static PawnHashInfo pawnHashtable[MAX_THREADS][PAWN_HASHTABLE_SIZE]; 
-   
- Hashtable *getSharedHashtable() 
- { 
-    return &sharedHashtable; 
- } 
-   
- int setNumberOfThreads(int _numThreads) 
- { 
-    numThreads = max(1, min(MAX_THREADS, _numThreads)); 
-   
-    return numThreads; 
- } 
-   
- int getNumberOfThreads() 
- { 
-    return numThreads; 
- } 
-   
- UINT64 getNodeCount(void) 
- { 
-    int threadCount; 
-    UINT64 sum = 0; 
-   
-    for (threadCount = 0; threadCount < numThreads; threadCount++) 
-    { 
-       sum += variations[threadCount].nodes; 
-    } 
-   
-    return sum; 
- } 
-   
- Variation *getCurrentVariation() 
- { 
-    return &variations[0]; 
- } 
-   
- void getGuiSearchMutex(void) 
- { 
- #ifdef DEBUG_COORDINATION 
-    logDebug("aquiring search lock...\n"); 
- #endif 
-   
- #ifndef _MSC_VER 
-    pthread_mutex_lock(&guiSearchMutex); 
- #else // _MSC_VER 
-    while (guiSearchMutex) 
-       Sleep (10); // allow context switching 
-    guiSearchMutex = true; // Pierre-Marie Baty -- mutex support on Win32 
- #endif // !_MSC_VER 
-   
- #ifdef DEBUG_COORDINATION 
-    logDebug("search lock aquired...\n"); 
- #endif 
- } 
-   
- void releaseGuiSearchMutex(void) 
- { 
- #ifndef _MSC_VER 
-    pthread_mutex_unlock(&guiSearchMutex); 
- #else // _MSC_VER 
-    guiSearchMutex = false; // Pierre-Marie Baty -- mutex support on Win32 
- #endif // !_MSC_VER 
-   
- #ifdef DEBUG_COORDINATION 
-    logDebug("search lock released...\n"); 
- #endif 
- } 
-   
- static int startSearch(Variation * currentVariation) 
- { 
-    currentVariation->searchStatus = SEARCH_STATUS_RUNNING; 
-   
- #ifdef DEBUG_COORDINATION 
-    logDebug("Search with thread #%d started.\n", 
-             currentVariation->threadNumber); 
- #endif 
-   
-    switch (currentTask->type) 
-    { 
-    case TASKTYPE_BEST_MOVE: 
-       currentTask->bestMove = search(currentVariation, NULL); 
-       break; 
-   
-    case TASKTYPE_TEST_BEST_MOVE: 
-       currentTask->bestMove = 
-          search(currentVariation, ¤tTask->solutions); 
-       break; 
-   
-    case TASKTYPE_MATE_IN_N: 
-       searchForMate(currentVariation, 
-                     ¤tTask->calculatedSolutions, 
-                     currentTask->numberOfMoves); 
-       break; 
-   
-    case TASKTYPE_TEST_MATE_IN_N: 
-       searchForMate(currentVariation, 
-                     ¤tTask->calculatedSolutions, 
-                     currentTask->numberOfMoves); 
-       break; 
-   
-    default: 
-       break; 
-    } 
-   
-    currentTask->nodes = getNodeCount(); 
-   
-    if (currentVariation->threadNumber == 0) 
-    { 
-       int threadCount; 
-   
-       for (threadCount = 1; threadCount < numThreads; threadCount++) 
-       { 
-          variations[threadCount].terminate = TRUE; 
-       } 
-   
- #ifndef _MSC_VER 
-       pthread_cancel(timer); 
- #else // _MSC_VER 
-       terminate_timer = true; // Pierre-Marie Baty -- Win32 threads support 
- #endif // !_MSC_VER 
-    } 
-   
- #ifdef DEBUG_COORDINATION 
-    logDebug("Search thread #%d terminated.\n", 
-             currentVariation->threadNumber); 
- #endif 
-   
-    currentVariation->searchStatus = SEARCH_STATUS_FINISHED; 
-   
-    return 0; 
- } 
-   
- long getElapsedTime() 
- { 
-    return getTimestamp() - variations[0].startTime; 
- } 
-   
- static THREAD_RETURN_TYPE executeSearch(void *arg) 
- { 
-    Variation *currentVariation = arg; 
-   
- #ifdef _MSC_VER 
-    currentVariation->finished = false; // Pierre-Marie Baty -- Win32 thread control 
- #endif // _MSC_VER 
-   
-    startSearch(currentVariation); 
-   
- #ifdef _MSC_VER 
-    currentVariation->finished = true; // Pierre-Marie Baty -- Win32 thread control 
- #endif // _MSC_VER 
-    return 0; 
- } 
-   
- static THREAD_RETURN_TYPE watchTime(void *arg) 
- { 
-    Variation *currentVariation = arg; 
-    long timeLimit = currentVariation->timeLimit; 
-    struct timespec requested;// , remaining; // Pierre-Marie Baty -- unused variable 
-    int result; 
-   
-    requested.tv_sec = timeLimit / 1000; 
-    requested.tv_nsec = 1000000 * (timeLimit - 1000 * (long)requested.tv_sec); // Pierre-Marie Baty -- added type cast 
-   
-    /* logReport("### Timer thread working sec=%ld nsec=%ld ###\n", 
-       requested.tv_sec, requested.tv_nsec); */ 
- #ifndef _MSC_VER 
-    result = nanosleep(&requested, &remaining); 
-    if (result != -1) 
- #else // _MSC_VER 
-    result  = (clock () * 1000 /-  CLOCKS_PER_SEC ); // in milliseconds
-    while (!- terminate_timer  && ((clock () * 1000 /-  CLOCKS_PER_SEC ) <-  result  +-  timeLimit ))
 
-       Sleep (10); // allow context switching if necessary 
-    if (!terminate_timer) 
- #endif // !_MSC_VER 
-    { 
-       getGuiSearchMutex(); 
-       prepareSearchAbort(); 
-       releaseGuiSearchMutex(); 
-    } 
-   
-    return 0; 
- } 
-   
- void startTimerThread(SearchTask * task) 
- { 
-    if (task->variation->timeLimit > 0 && task->variation->ponderMode == FALSE) 
-    { 
- #ifndef _MSC_VER 
-       if (pthread_create(&timer, NULL, &watchTime, task->variation) == 0) 
- #else // _MSC_VER 
-       terminate_timer = false; // Pierre-Marie Baty -- Win32 threads support 
-       if ((timer = _beginthread (watchTime, 0, task->variation)) != -1) // Pierre-Marie Baty -- Win32 threads support 
- #endif // !_MSC_VER 
-       { 
- #ifdef DEBUG_COORDINATION 
-          logDebug("Timer thread started.\n"); 
- #endif 
-       } 
-       else 
-       { 
-          logDebug("### Timer thread could not be started. ###\n"); 
-   
-       } 
-    } 
- } 
-   
- void scheduleTask(SearchTask * task) 
- { 
-    const unsigned long startTime = getTimestamp(); 
-    int threadCount; 
-   
-    sharedHashtable.entriesUsed = 0; 
-   
-    startTimerThread(task); 
-   
-    for (threadCount = 0; threadCount < numThreads; threadCount++) 
-    { 
-       Variation *currentVariation = &variations[threadCount]; 
-   
-       currentTask = task; 
-       *currentVariation = *(currentTask->variation); 
-       currentVariation->searchStatus = SEARCH_STATUS_TERMINATE; 
-       currentVariation->bestBaseMove = NO_MOVE; 
-       currentVariation->terminate = FALSE; 
-       currentVariation->pawnHashtable = &(pawnHashtable[threadCount][0]); 
-       currentVariation->kingsafetyHashtable = 
-          &(kingSafetyHashtable[threadCount][0]); 
-       currentVariation->threadNumber = threadCount; 
-       currentVariation->startTime = startTime; 
-   
- #ifndef _MSC_VER 
-       if (pthread_create(&searchThread[threadCount], NULL, 
-                          &executeSearch, currentVariation) == 0) 
- #else // _MSC_VER 
-       if ((searchThread[threadCount] = _beginthread(executeSearch, 0, currentVariation)) != -1) // Pierre-Marie Baty -- Win32 threads support 
- #endif // !_MSC_VER 
-       { 
- #ifdef DEBUG_COORDINATION 
-          logDebug("Search thread #%d created.\n", threadCount); 
- #endif 
-       } 
-       else 
-       { 
-          logDebug("### Search thread #%d could not be started. ###\n", 
-                   threadCount); 
-   
-       } 
-    } 
- } 
-   
- void waitForSearchTermination(void) 
- { 
-    int threadCount; 
-    bool finished; 
-    int count = 0; 
-   
-    do 
-    { 
-       finished = TRUE; 
-   
-       if (count > 1000) 
-       { 
-          logDebug("waiting for search termination.\n"); 
-          count = 0; 
-       } 
-   
-       for (threadCount = 0; threadCount < numThreads; threadCount++) 
-       { 
-          Variation *currentVariation = &variations[threadCount]; 
-   
-          if (currentVariation->searchStatus != SEARCH_STATUS_FINISHED) 
-          { 
-             if (searchThread[threadCount] != INVALID_THREAD_ID) 
-             { 
- #ifndef _MSC_VER 
-                const int result = pthread_join (searchThread[threadCount], 0); 
-   
-                if (result == 0) 
-                { 
-                   searchThread[threadCount] = INVALID_THREAD_ID; 
-                } 
-                else 
-                { 
-                   finished = FALSE; 
-                } 
- #else // _MSC_VER 
-                while (!currentVariation->finished) 
-                   Sleep (10); // allow context switching 
-   
-                searchThread[threadCount] = INVALID_THREAD_ID; 
- #endif // !_MSC_VER 
-             } 
-          } 
-          else 
-          { 
-             searchThread[threadCount] = INVALID_THREAD_ID; 
-          } 
-   
- #ifdef DEBUG_COORDINATION 
-          logDebug("Task %d finished.\n", threadCount); 
- #endif 
-       } 
-   
-       count++; 
-    } 
-    while (finished == FALSE); 
- } 
-   
- void completeTask(SearchTask * task) 
- { 
-    scheduleTask(task); 
-   
- #ifdef DEBUG_COORDINATION 
-    logDebug("Task scheduled. Waiting for completion.\n"); 
- #endif 
-   
-    waitForSearchTermination(); 
- } 
-   
- void prepareSearchAbort(void) 
- { 
-    int threadCount; 
-   
-    for (threadCount = 0; threadCount < numThreads; threadCount++) 
-    { 
-       variations[threadCount].terminate = TRUE; 
-    } 
- } 
-   
- void unsetPonderMode(void) 
- { 
-    int threadCount; 
-   
-    for (threadCount = 0; threadCount < numThreads; threadCount++) 
-    { 
-       Variation *currentVariation = &variations[threadCount]; 
-   
-       currentVariation->ponderMode = FALSE; 
-    } 
- } 
-   
- /*void setTimeLimit(unsigned long timeTarget, unsigned long timeLimit) 
- { 
-    int threadCount; 
-   
-    for (threadCount = 0; threadCount < numThreads; threadCount++) 
-    { 
-       Variation *currentVariation = &variations[threadCount]; 
-   
-       currentVariation->timeTarget = timeTarget; 
-       currentVariation->timeLimit = timeLimit; 
-    } 
- }*/ // Pierre-Marie Baty -- unused function? 
-   
- void setHashtableSizeInMb(unsigned int size) 
- { 
-    UINT64 tablesize = 1024 * 1024 * (UINT64) size; 
-   
-    setHashtableSize(&sharedHashtable, tablesize); 
-    resetHashtable(&sharedHashtable); 
- } 
-   
- int initializeModuleCoordination() 
- { 
-    int threadCount; 
-   
-    initializeHashtable(&sharedHashtable); 
-    setHashtableSize(&sharedHashtable, 16 * 1024 * 1024); 
-    resetHashtable(&sharedHashtable); 
-   
-    for (threadCount = 0; threadCount < MAX_THREADS; threadCount++) 
-    { 
-       Variation *currentVariation = &variations[threadCount]; 
-   
-       currentVariation->searchStatus = SEARCH_STATUS_FINISHED; 
-    } 
-   
-    return 0; 
- } 
-   
- int testModuleCoordination() 
- { 
-    return 0; 
- } 
-