Esempio n. 1
0
	void NodeVersionLoader::startDownload()
	{
		auto self = shared_from_this();
		checkThread();
		
		auto& item = currentDownloadItem();
		{
			std::lock_guard<std::mutex> lock(downloadQueueMutex);
			--item.retryCount;
		}
		
		state = State::Connecting;
		log.setChannel("Download:" + item.version);
		
		std::string fileName;
		auto ver = item.version;
		try {
			onNeedsDownloadFileName(ver, fileName);
			if (fileName.empty()) {
				MSCThrow(InvalidOperationException("File name is empty."));
			}
		} catch (...) {
			downloadFailed("Failed to determine the downloaded file path.: " +
						   boost::current_exception_diagnostic_information());
			return;
		}
		try {
			file.reset(new std::ofstream(fileName.c_str(),
										 std::ios::out |
										 std::ios::trunc |
										 std::ios::binary));
			
			file->exceptions(std::ios::failbit |
							 std::ios::badbit);
		} catch (...) {
			file.reset();
			downloadFailed("Failed to open the destination file '" + fileName + "'.: " +
						   boost::current_exception_diagnostic_information());
			return;
		}
		
		BOOST_LOG_SEV(log, LogLevel::Info) <<
		"Connecting to the master server.";
		
		socket.async_connect(endpoint, [this, self, &item](const error_code& error) {
			checkThread();
			
			if (disposed) {
				downloadCancelled();
				return;
			}
			if (error) {
				downloadFailed(error.message());
				return;
			}
			
			sendHeader();
		});
	}
Esempio n. 2
0
	void NodeVersionLoader::receiveHeader()
	{
		auto self = shared_from_this();
		checkThread();
		
		auto& item = currentDownloadItem();
		
		state = State::ReceivingHeader;
		
		auto buf = std::make_shared<std::uint64_t>();
		
		timer.expires_from_now(boost::posix_time::seconds(8));
		timer.async_wait([this, self] (const error_code& error) {
			if (error) {
				return;
			}
			if (disposed) {
				return;
			}
			if (state == State::ReceivingHeader) {
				BOOST_LOG_SEV(log, LogLevel::Warn) <<
				"Timed out.";
				socket.cancel();
			}
		});
		
		asio::async_read(socket, asio::buffer(buf.get(), 8), [this, self, &item, buf](const error_code& error, std::size_t) {
			checkThread();
			
			if (disposed) {
				downloadCancelled();
				return;
			}
			if (error) {
				downloadFailed(error.message());
				return;
			}
			timer.cancel();
			
			auto size = *buf;
			if (size == 0) {
				downloadFailed("Version cannot be downloaded for some reason.");
				return;
			}
			
			receiveData(size);
		});
	}
Esempio n. 3
0
	void NodeVersionLoader::setWatchDogTimer()
	{
		auto self = shared_from_this();
		checkThread();
		
		timer.expires_from_now(boost::posix_time::seconds(3));
		timer.async_wait([this, self] (const error_code& error) {
			if (error) {
				return;
			}
			if (disposed) {
				return;
			}
			if (state == State::ReceivingData) {
				auto now = boost::posix_time::second_clock::local_time();
				if (now - lastReceiveTime > boost::posix_time::seconds(10)) {
					BOOST_LOG_SEV(log, LogLevel::Warn) <<
					"Timed out.";
					socket.cancel();
				} else {
					setWatchDogTimer();
				}
			}
		});
	}
Esempio n. 4
0
ThreadState::ThreadState()
    : m_thread(currentThread())
    , m_persistents(adoptPtr(new PersistentAnchor()))
    , m_startOfStack(reinterpret_cast<intptr_t*>(getStackStart()))
    , m_endOfStack(reinterpret_cast<intptr_t*>(getStackStart()))
    , m_safePointScopeMarker(nullptr)
    , m_atSafePoint(false)
    , m_interruptors()
    , m_didV8GCAfterLastGC(false)
    , m_sweepForbidden(false)
    , m_noAllocationCount(0)
    , m_isTerminating(false)
    , m_shouldFlushHeapDoesNotContainCache(false)
    , m_collectionRate(1.0)
    , m_gcState(NoGCScheduled)
    , m_traceDOMWrappers(nullptr)
#if defined(ADDRESS_SANITIZER)
    , m_asanFakeStack(__asan_get_current_fake_stack())
#endif
{
    checkThread();
    ASSERT(!**s_threadSpecific);
    **s_threadSpecific = this;

    if (isMainThread()) {
        s_mainThreadStackStart = reinterpret_cast<uintptr_t>(m_startOfStack) - sizeof(void*);
        s_mainThreadUnderestimatedStackSize = getUnderestimatedStackSize() - sizeof(void*);
    }

    for (int heapIndex = 0; heapIndex < NumberOfHeaps; heapIndex++)
        m_heaps[heapIndex] = new ThreadHeap(this, heapIndex);

    m_weakCallbackStack = new CallbackStack();
}
Esempio n. 5
0
	void NodeVersionLoader::checkQueue()
	{
		auto self = shared_from_this();
		checkThread();
		
		if (isDownloading())
			return;
		
		while (true) {
			{
				std::lock_guard<std::mutex> lock(downloadQueueMutex);
				if (downloadQueue.empty())
					return;
				
				auto& item = downloadQueue.front();
				bool cancel = false;
				try {
					onVersionAboutToBeDownloaded(item.version, cancel);
				} catch (...) {
					BOOST_LOG_SEV(log, LogLevel::Error) <<
					"onVersionAboutToBeDownloaded failed: " <<
					boost::current_exception_diagnostic_information();
					cancel = true;
				}
				if (cancel) {
					downloadQueue.erase(downloadQueue.begin());
					continue;
				}
				
			}
			
			startDownload();
		}
	}
Esempio n. 6
0
void ThreadState::postGCProcessing()
{
    checkThread();
    if (gcState() != EagerSweepScheduled && gcState() != LazySweepScheduled)
        return;

    m_didV8GCAfterLastGC = false;
    if (isMainThread())
        m_allocatedObjectSizeBeforeSweeping = Heap::allocatedObjectSize();

#if ENABLE(GC_PROFILE_HEAP)
    // We snapshot the heap prior to sweeping to get numbers for both resources
    // that have been allocated since the last GC and for resources that are
    // going to be freed.
    bool gcTracingEnabled;
    TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink_gc", &gcTracingEnabled);
    if (gcTracingEnabled)
        snapshot();
#endif

    {
        if (isMainThread())
            ScriptForbiddenScope::enter();

        SweepForbiddenScope forbiddenScope(this);
        {
            // Disallow allocation during weak processing.
            NoAllocationScope noAllocationScope(this);
            {
                TRACE_EVENT0("blink_gc", "ThreadState::threadLocalWeakProcessing");
                // Perform thread-specific weak processing.
                while (popAndInvokeWeakPointerCallback(Heap::s_markingVisitor)) { }
            }
            {
                TRACE_EVENT0("blink_gc", "ThreadState::invokePreFinalizers");
                invokePreFinalizers(*Heap::s_markingVisitor);
            }
        }

        if (isMainThread())
            ScriptForbiddenScope::exit();
    }

#if ENABLE(OILPAN)
    if (gcState() == EagerSweepScheduled) {
        // Eager sweeping should happen only in testing.
        setGCState(Sweeping);
        completeSweep();
    } else {
        // The default behavior is lazy sweeping.
        setGCState(Sweeping);
    }
#else
    // FIXME: For now, we disable lazy sweeping in non-oilpan builds
    // to avoid unacceptable behavior regressions on trunk.
    setGCState(Sweeping);
    completeSweep();
#endif
}
Esempio n. 7
0
	void NodeVersionLoader::sendHeader()
	{
		auto self = shared_from_this();
		checkThread();
		
		auto& item = currentDownloadItem();
		
		state = State::SendingHeader;
		
		PacketGenerator gen;
		gen.write(VersionDownloadRequestMagic);
		gen.writeString(item.version);
		
		auto buf = std::make_shared<std::vector<char>>(std::move(gen.vector()));
		
		timer.expires_from_now(boost::posix_time::seconds(8));
		timer.async_wait([this, self] (const error_code& error) {
			if (error) {
				return;
			}
			if (disposed) {
				return;
			}
			if (state == State::SendingHeader) {
				BOOST_LOG_SEV(log, LogLevel::Warn) <<
				"Timed out.";
				socket.cancel();
			}
		});
		
		asio::async_write(socket, asio::buffer(buf->data(), buf->size()), [this, self, &item](const error_code& error, std::size_t) {
			checkThread();
			
			if (disposed) {
				downloadCancelled();
				return;
			}
			if (error) {
				downloadFailed(error.message());
				return;
			}
			timer.cancel();
			
			receiveHeader();
		});
	}
Esempio n. 8
0
void Server::remove(Connection* connection) {
    checkThread();
    epoll_event event = { 0, { connection } };
    if (epoll_ctl(_epollFd, EPOLL_CTL_DEL, connection->getFd(), &event) == -1) {
        LS_ERROR(_logger, "Unable to remove from epoll: " << getLastError());
    }
    _connections.erase(connection);
}
Esempio n. 9
0
/*
 * Class:     com_Revsoft_Wabbitemu_CalcInterface
 * Method:    CreateRom
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 */
JNIEXPORT jint JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_CreateRom
	(JNIEnv *env, jclass classObj, jstring jOsPath, jstring jBootPath,
			jstring jRomPath, jint model) {
	checkThread();
	const char *osPath = env->GetStringUTFChars(jOsPath, JNI_FALSE);
	const char *bootPath = env->GetStringUTFChars(jBootPath, JNI_FALSE);
	const char *romPath = env->GetStringUTFChars(jRomPath, JNI_FALSE);

	//Do not allow more than one calc currently
	if (lpCalc) {
		calc_slot_free(lpCalc);
	}

	lpCalc = calc_slot_new();
	calc_init_model(lpCalc, model, NULL);

	//slot stuff
	strcpy(lpCalc->rom_path, romPath);
	lpCalc->active = TRUE;
	lpCalc->model = (CalcModel) model;
	lpCalc->cpu.pio.model = model;
	FILE *file = fopen(bootPath, "rb");
	if (file == NULL) {
		calc_slot_free(lpCalc);
		lpCalc = NULL;
		return -1;
	}
	writeboot(file, &lpCalc->mem_c, -1);
	fclose(file);
	remove(bootPath);
	TIFILE_t *tifile = importvar(osPath, FALSE);
	if (tifile == NULL) {
		calc_slot_free(lpCalc);
		lpCalc = NULL;
		return -2;
	}
	int link_error = forceload_os(&lpCalc->cpu, tifile);
	if (link_error != LERR_SUCCESS) {
		calc_slot_free(lpCalc);
		lpCalc = NULL;
		return -2;
	}

	calc_erase_certificate(lpCalc->mem_c.flash,lpCalc->mem_c.flash_size);
	calc_reset(lpCalc);
	//write the output from file
	MFILE *romfile = ExportRom((char *) romPath, lpCalc);
	if (romfile != NULL) {
		mclose(romfile);
		calc_slot_free(lpCalc);
		lpCalc = NULL;
		return 0;
	}

	calc_slot_free(lpCalc);
	lpCalc = NULL;
	return -3;
}
Esempio n. 10
0
void ThreadState::addInterruptor(Interruptor* interruptor)
{
    checkThread();
    SafePointScope scope(HeapPointersOnStack, SafePointScope::AllowNesting);
    {
        MutexLocker locker(threadAttachMutex());
        m_interruptors.append(interruptor);
    }
}
Esempio n. 11
0
/*
 * Class:     com_Revsoft_Wabbitemu_CalcInterface
 * Method:    ReleaseKey
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_ReleaseKey
  (JNIEnv *env, jclass classObj, jint group, jint bit) {
	checkThread();
	if (!lpCalc) {
		return;
	}

	keypad_release(&lpCalc->cpu, (int) group, (int) bit);
}
Esempio n. 12
0
/*
 * Class:     com_Revsoft_Wabbitemu_CalcInterface
 * Method:    ClearKeys
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_ClearKeys
  (JNIEnv *env, jclass classObj) {
	checkThread();
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 8; j++) {

		}
	}
}
Esempio n. 13
0
/*
 * Class:     com_Revsoft_Wabbitemu_CalcInterface
 * Method:    UnpauseCalc
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_UnpauseCalc
  (JNIEnv *env, jclass classObj) {
	checkThread();
	if (!lpCalc) {
		return;
	}

	lpCalc->running = TRUE;
}
Esempio n. 14
0
void ThreadState::leaveSafePoint(SafePointAwareMutexLocker* locker)
{
    checkThread();
    ASSERT(m_atSafePoint);
    s_safePointBarrier->leaveSafePoint(this, locker);
    m_atSafePoint = false;
    m_stackState = HeapPointersOnStack;
    clearSafePointScopeMarker();
    postGCProcessing();
}
Esempio n. 15
0
JNIEXPORT void JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_ResetCalc
		(JNIEnv *env, jclass classObj) {
	checkThread();
	if (!lpCalc) {
		return;
	}

	lpCalc->fake_running = TRUE;
	calc_reset(lpCalc);
	lpCalc->fake_running = FALSE;
}
Esempio n. 16
0
void ThreadState::runScheduledGC(StackState stackState)
{
    checkThread();
    if (stackState == NoHeapPointersOnStack) {
        if (gcState() == GCScheduledForTesting) {
            Heap::collectAllGarbage();
        } else if (gcState() == GCScheduled) {
            Heap::collectGarbage(NoHeapPointersOnStack, GCWithoutSweep);
        }
    }
}
Esempio n. 17
0
void ThreadState::removeInterruptor(Interruptor* interruptor)
{
    checkThread();
    SafePointScope scope(HeapPointersOnStack, SafePointScope::AllowNesting);
    {
        MutexLocker locker(threadAttachMutex());
        size_t index = m_interruptors.find(interruptor);
        RELEASE_ASSERT(index >= 0);
        m_interruptors.remove(index);
    }
}
Esempio n. 18
0
JNIEXPORT jint JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_LoadFile
		(JNIEnv *env, jclass classObj, jstring filePath) {
	checkThread();
	const char *path = env->GetStringUTFChars(filePath, JNI_FALSE);
	TIFILE_t *tifile = importvar(path, TRUE);
	if (!tifile || !lpCalc) {
		return (jint) LERR_FILE;
	}

	int result = SendFile(lpCalc, path, SEND_CUR);
	return result;
}
Esempio n. 19
0
	void NodeVersionLoader::receiveData(std::uint64_t size)
	{
		auto self = shared_from_this();
		checkThread();
		
		state = State::ReceivingData;
		remainingBytes = size;
		lastReceiveTime = boost::posix_time::second_clock::local_time();
		
		setWatchDogTimer();
		receiveChunk();
	}
Esempio n. 20
0
void ThreadState::cleanup()
{
    checkThread();
    // Finish sweeping.
    completeSweep();
    {
        // Grab the threadAttachMutex to ensure only one thread can shutdown at
        // a time and that no other thread can do a global GC. It also allows
        // safe iteration of the attachedThreads set which happens as part of
        // thread local GC asserts. We enter a safepoint while waiting for the
        // lock to avoid a dead-lock where another thread has already requested
        // GC.
        SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnStack);

        // From here on ignore all conservatively discovered
        // pointers into the heap owned by this thread.
        m_isTerminating = true;

        // Set the terminate flag on all heap pages of this thread. This is used to
        // ensure we don't trace pages on other threads that are not part of the
        // thread local GC.
        prepareHeapForTermination();

        // Do thread local GC's as long as the count of thread local Persistents
        // changes and is above zero.
        PersistentAnchor* anchor = static_cast<PersistentAnchor*>(m_persistents.get());
        int oldCount = -1;
        int currentCount = anchor->numberOfPersistents();
        ASSERT(currentCount >= 0);
        while (currentCount != oldCount) {
            Heap::collectGarbageForTerminatingThread(this);
            oldCount = currentCount;
            currentCount = anchor->numberOfPersistents();
        }
        // We should not have any persistents left when getting to this point,
        // if we have it is probably a bug so adding a debug ASSERT to catch this.
        ASSERT(!currentCount);
        // All of pre-finalizers should be consumed.
        ASSERT(m_preFinalizers.isEmpty());
        RELEASE_ASSERT(gcState() == NoGCScheduled);

        // Add pages to the orphaned page pool to ensure any global GCs from this point
        // on will not trace objects on this thread's heaps.
        cleanupPages();

        ASSERT(attachedThreads().contains(this));
        attachedThreads().remove(this);
    }

    for (auto& task : m_cleanupTasks)
        task->postCleanup();
    m_cleanupTasks.clear();
}
Esempio n. 21
0
void ThreadState::safePoint(StackState stackState)
{
    checkThread();
    runScheduledGC(stackState);
    ASSERT(!m_atSafePoint);
    m_stackState = stackState;
    m_atSafePoint = true;
    s_safePointBarrier->checkAndPark(this);
    m_atSafePoint = false;
    m_stackState = HeapPointersOnStack;
    postGCProcessing();
}
Esempio n. 22
0
void ThreadState::setGCState(GCState gcState)
{
    switch (gcState) {
    case NoGCScheduled:
        checkThread();
        RELEASE_ASSERT(m_gcState == Sweeping);
        break;
    case GCScheduled:
    case GCScheduledForTesting:
        checkThread();
        RELEASE_ASSERT(m_gcState == NoGCScheduled || m_gcState == GCScheduled || m_gcState == GCScheduledForTesting || m_gcState == StoppingOtherThreads || m_gcState == SweepingAndNextGCScheduled);
        completeSweep();
        break;
    case StoppingOtherThreads:
        checkThread();
        RELEASE_ASSERT(m_gcState == NoGCScheduled || m_gcState == GCScheduled || m_gcState == GCScheduledForTesting || m_gcState == Sweeping || m_gcState == SweepingAndNextGCScheduled);
        completeSweep();
        break;
    case GCRunning:
        ASSERT(!isInGC());
        RELEASE_ASSERT(m_gcState != GCRunning);
        break;
    case EagerSweepScheduled:
    case LazySweepScheduled:
        ASSERT(isInGC());
        RELEASE_ASSERT(m_gcState == GCRunning);
        break;
    case Sweeping:
        checkThread();
        RELEASE_ASSERT(m_gcState == EagerSweepScheduled || m_gcState == LazySweepScheduled);
        break;
    case SweepingAndNextGCScheduled:
        checkThread();
        RELEASE_ASSERT(m_gcState == Sweeping || m_gcState == SweepingAndNextGCScheduled);
        break;
    default:
        ASSERT_NOT_REACHED();
    }
    m_gcState = gcState;
}
Esempio n. 23
0
int main (int argc, const char * argv[]) 
{
    int port = DEFAULT_PORT;    
    int bufferSize = DEFAULT_BUFFER_SIZE;
    bool isQuiet = DEFAULT_QUIET;
    bool isDebug = DEFAULT_DEBUG;
    int maxClient = DEFAULT_MAXCLIENT;

    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);
    
    readArgs(argc,argv,&port,&bufferSize,&isQuiet,&isDebug,&maxClient);

    logger.setQuiet(isQuiet);
    logger.setDebug(isDebug);
    
    if(!isQuiet)
    {
        printInfo(port,bufferSize,isDebug,maxClient);
    }
    
    List<Client*> list;
    sf::Mutex listMutex;

    sf::SocketSelector selector;
    
    Buffer exchangeBuffer;
    setupExchangeBuffer(&exchangeBuffer, bufferSize);

    logger.printLog("Init'ed ...");
    
    ClientsContainer container(&list,&listMutex,&selector);
    
    
    sf::Thread answerThread(&answerToClient,AnswerDataSet(&container,port,maxClient));
    answerThread.launch();


    sf::Thread checkThread(&checkForInputs,CheckDataSet(&container,&exchangeBuffer));
    checkThread.launch();
    
    while(1) //TODO graphic stats
    {
        if(checkStopThreads())
        {
            break;
        }
        sf::sleep(sf::milliseconds(5));
    }
    
    return 0;
}
Esempio n. 24
0
	void NodeVersionLoader::downloadFailed(const std::string& msg)
	{
		auto self = shared_from_this();
		checkThread();
		
		auto& item = currentDownloadItem();
		
		file.reset();
		
		int retryCount;
		{
			std::lock_guard<std::mutex> lock(downloadQueueMutex);
			retryCount = item.retryCount;
		}
		if (retryCount == 0) {
			BOOST_LOG_SEV(log, LogLevel::Error) <<
			"Failed to download.: " << msg;
			
			auto ver = item.version;
			{
				std::lock_guard<std::mutex> lock(downloadQueueMutex);
				downloadQueue.pop_front();
				// note: `item` is a dangling reference now
			}
			
			onVersionDownloadFailed(ver);
			
		} else {
			BOOST_LOG_SEV(log, LogLevel::Warn) <<
			"Failed to download. Retrying.: " << msg;
		}
		
		log.setChannel(std::string("(none)"));
		
		state = State::Waiting;
		timer.expires_from_now(boost::posix_time::seconds(3));
		timer.async_wait([this, self] (const error_code& error) {
			if (error) {
				return;
			}
			if (disposed) {
				BOOST_LOG_SEV(log, LogLevel::Debug) <<
				"Retry timer aborted.: Disposed.";
				return;
			}
			state = State::Idle;
			checkQueue();
		});
		
	}
Esempio n. 25
0
ThreadState::~ThreadState()
{
    checkThread();
    delete m_weakCallbackStack;
    m_weakCallbackStack = nullptr;
    for (int i = 0; i < NumberOfHeaps; ++i)
        delete m_heaps[i];
    deleteAllValues(m_interruptors);
    **s_threadSpecific = nullptr;
    if (isMainThread()) {
        s_mainThreadStackStart = 0;
        s_mainThreadUnderestimatedStackSize = 0;
    }
}
Esempio n. 26
0
/*
 * Class:     com_Revsoft_Wabbitemu_CalcInterface
 * Method:    SetCacheDir
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_Initialize
		(JNIEnv *env, jclass classObj, jstring filePath) {
	checkThread();
	const char *path = env->GetStringUTFChars(filePath, JNI_FALSE);
	strcpy(cache_dir, path);
	lpCalc = calc_slot_new();
	lpCalc->model = INVALID_MODEL;
	calc_register_event(lpCalc, ROM_LOAD_EVENT, &load_settings, NULL);

	for (int i = 0; i < 256; i++) {
		redPalette[i] = (0x9E * (256 - i)) / 255;
		bluePalette[i] = (0x88 * (256 - i)) / 255;
		greenPalette[i] = (0xAB * (256 - i)) / 255;
	}
}
Esempio n. 27
0
void ThreadState::enterSafePoint(StackState stackState, void* scopeMarker)
{
    checkThread();
#ifdef ADDRESS_SANITIZER
    if (stackState == HeapPointersOnStack)
        scopeMarker = adjustScopeMarkerForAdressSanitizer(scopeMarker);
#endif
    ASSERT(stackState == NoHeapPointersOnStack || scopeMarker);
    runScheduledGC(stackState);
    ASSERT(!m_atSafePoint);
    m_atSafePoint = true;
    m_stackState = stackState;
    m_safePointScopeMarker = scopeMarker;
    s_safePointBarrier->enterSafePoint(this);
}
Esempio n. 28
0
void ThreadState::scheduleGCOrForceConservativeGCIfNeeded()
{
    checkThread();
    // Allocation is allowed during sweeping, but those allocations should not
    // trigger nested GCs
    if (isSweepingInProgress())
        return;
    ASSERT(!sweepForbidden());

    if (!shouldGC())
        return;
    if (shouldForceConservativeGC())
        Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::GCWithoutSweep);
    else
        scheduleGC();
}
Esempio n. 29
0
/*
 * Class:     com_Revsoft_Wabbitemu_CalcInterface
 * Method:    SaveCalcState
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT jboolean JNICALL Java_com_Revsoft_Wabbitemu_calc_CalcInterface_SaveCalcState
		(JNIEnv *env, jclass classObj, jstring filePath) {
	checkThread();
	const char *path = env->GetStringUTFChars(filePath, JNI_FALSE);

    SAVESTATE_t *save;
    try {
        save = SaveSlot(lpCalc, "Wabbitemu", "Automatic save state");
    } catch (std::exception &e) {
        _tprintf_s(_T("Exception loading save state: %s"), e.what());
        return FALSE;
    }
	if (save != NULL) {
		WriteSave(path, save, ZLIB_CMP);
		FreeSave(save);
	}

	return (jboolean) (save != NULL);
}
Esempio n. 30
0
void Thread::waitForThread() {  //waits for thread
	if(checkThread()) pthread_join(handle, NULL);  //if a thread has been created wait for it to die
}