Beispiel #1
0
bool
MM_EnvironmentBase::tryAcquireExclusiveVMAccessForGC(MM_Collector *collector)
{
	MM_GCExtensionsBase *extensions = getExtensions();
	uintptr_t collectorAccessCount = collector->getExclusiveAccessCount();

	_exclusiveAccessBeatenByOtherThread = false;

	while(_omrVMThread != extensions->gcExclusiveAccessThreadId) {
		if(NULL == extensions->gcExclusiveAccessThreadId) {
			/* there is a chance the thread can win the race to acquiring exclusive for GC */
			omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
			if(NULL == extensions->gcExclusiveAccessThreadId) {
				/* thread is the winner and will request the GC */
				extensions->gcExclusiveAccessThreadId = _omrVMThread;
			}
			omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);
		}

		if(_omrVMThread != extensions->gcExclusiveAccessThreadId) {
			/* thread was not the winner for requesting a GC - allow the GC to proceed and wait for it to complete */
			Assert_MM_true(NULL != extensions->gcExclusiveAccessThreadId);

			uintptr_t accessMask;
			_envLanguageInterface->releaseCriticalHeapAccess(&accessMask);

			/* there is a chance the GC will already have executed at this point or other threads will re-win and re-execute.  loop until the
			 * thread sees that no more GCs are being requested.
			 */
			omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
			while(NULL != extensions->gcExclusiveAccessThreadId) {
				omrthread_monitor_wait(extensions->gcExclusiveAccessMutex);
			}
			omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);

			_envLanguageInterface->reacquireCriticalHeapAccess(accessMask);

			/* May have been beaten to a GC, but perhaps not the one we wanted.  Check and if in fact the collection we intended has been
			 * completed, we will not acquire exclusive access.
			 */
			if(collector->getExclusiveAccessCount() != collectorAccessCount) {
				return false;
			}
		}
	}

	/* thread is the winner for requesting a GC (possibly through recursive calls).  proceed with acquiring exclusive access. */
	Assert_MM_true(_omrVMThread == extensions->gcExclusiveAccessThreadId);

	this->acquireExclusiveVMAccess();

	collector->incrementExclusiveAccessCount();

	GC_OMRVMInterface::flushCachesForGC(this);

	return true;
}
Beispiel #2
0
void
MM_MasterGCThread::masterThreadEntryPoint()
{
	OMR_VMThread *omrVMThread = NULL;
	Assert_MM_true(NULL != _collectorControlMutex);
	Assert_MM_true(NULL == _masterGCThread);

	/* Attach the thread as a system daemon thread */	
	/* You need a VM thread so that the stack walker can work */
	omrVMThread = MM_EnvironmentBase::attachVMThread(_extensions->getOmrVM(), "Dedicated GC Master", MM_EnvironmentBase::ATTACH_GC_MASTER_THREAD);
	if (NULL == omrVMThread) {
		/* we failed to attach so notify the creating thread that we should fail to start up */
		omrthread_monitor_enter(_collectorControlMutex);
		_masterThreadState = STATE_ERROR;
		omrthread_monitor_notify(_collectorControlMutex);
		omrthread_exit(_collectorControlMutex);
	} else {
		/* thread attached successfully */
		MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(omrVMThread);

		/* attachVMThread could allocate an execute a barrier (since it that point, this thread acted as a mutator thread.
		 * Flush GC chaches (like barrier buffers) before turning into the master thread */
		env->flushGCCaches();

		env->setThreadType(GC_MASTER_THREAD);

		/* Begin running the thread */
		omrthread_monitor_enter(_collectorControlMutex);
		
		_collector->preMasterGCThreadInitialize(env);
		
		_masterThreadState = STATE_WAITING;
		_masterGCThread = omrthread_self();
		omrthread_monitor_notify(_collectorControlMutex);
		do {
			if (STATE_GC_REQUESTED == _masterThreadState) {
				if (_runAsImplicit) {
					handleConcurrent(env);
				} else {
					handleSTW(env);
				}
			}

			if (STATE_WAITING == _masterThreadState) {
				if (_runAsImplicit || !handleConcurrent(env)) {
					omrthread_monitor_wait(_collectorControlMutex);
				}
			}
		} while (STATE_TERMINATION_REQUESTED != _masterThreadState);
		/* notify the other side that we are active so that they can continue running */
		_masterThreadState = STATE_TERMINATED;
		_masterGCThread = NULL;
		omrthread_monitor_notify(_collectorControlMutex);
		MM_EnvironmentBase::detachVMThread(_extensions->getOmrVM(), omrVMThread, MM_EnvironmentBase::ATTACH_GC_MASTER_THREAD);
		omrthread_exit(_collectorControlMutex);
	}
}
Beispiel #3
0
bool
MM_EnvironmentBase::tryAcquireExclusiveForConcurrentKickoff(MM_ConcurrentGCStats *stats)
{
	MM_GCExtensionsBase *extensions = MM_GCExtensionsBase::getExtensions(_omrVM);
	uintptr_t gcCount = extensions->globalGCStats.gcCount;

	while (_omrVMThread != extensions->gcExclusiveAccessThreadId) {
		if (NULL == extensions->gcExclusiveAccessThreadId) {
			/* there is a chance the thread can win the race to acquiring exclusive for GC */
			omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
			if (NULL == extensions->gcExclusiveAccessThreadId) {
				/* thread is the winner and will request the GC */
				extensions->gcExclusiveAccessThreadId =_omrVMThread ;
			}
			omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);
		}

		if (_omrVMThread != extensions->gcExclusiveAccessThreadId) {
			/* thread was not the winner for requesting a GC - allow the GC to proceed and wait for it to complete */
			Assert_MM_true(NULL != extensions->gcExclusiveAccessThreadId);

			uintptr_t accessMask = 0;

			_envLanguageInterface->releaseCriticalHeapAccess(&accessMask);

			/* there is a chance the GC will already have executed at this point or other threads will re-win and re-execute.  loop until the
			 * thread sees that no more GCs are being requested.
			 */
			omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
			while (NULL != extensions->gcExclusiveAccessThreadId) {
				omrthread_monitor_wait(extensions->gcExclusiveAccessMutex);
			}
			omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);

			_envLanguageInterface->reacquireCriticalHeapAccess(accessMask);

			/* May have been beaten to a GC, but perhaps not the one we wanted.  Check and if in fact the collection we intended has been
			 * completed, we will not acquire exclusive access.
			 */
			if ((gcCount != extensions->globalGCStats.gcCount) || (CONCURRENT_INIT_COMPLETE != stats->getExecutionMode())) {
				return false;
			}
		}
	}

	Assert_MM_true(_omrVMThread == extensions->gcExclusiveAccessThreadId);
	Assert_MM_true(CONCURRENT_INIT_COMPLETE == stats->getExecutionMode());

	/* thread is the winner for requesting a GC (possibly through recursive calls).  proceed with acquiring exclusive access. */
	this->acquireExclusiveVMAccess();

	return true;
}
Beispiel #4
0
/**
 * validates the following
 *
 * writer is excluded while another thread holds the rwmutex for write
 * once writer exits second writer can enter
 */
TEST(RWMutex, WriterExcludesWriterTesttryenter)
{
	SupportThreadInfo *info;
	omrthread_entrypoint_t functionsToRun[2];
	functionsToRun[0] = (omrthread_entrypoint_t) &enter_rwmutex_write;
	functionsToRun[1] = (omrthread_entrypoint_t) &exit_rwmutex_write;
	info = createSupportThreadInfo(functionsToRun, 2);

	/* first enter the mutex for write */
	ASSERT_TRUE(0 == info->writeCounter);
	omrthread_rwmutex_try_enter_write(info->handle);

	/* start the concurrent thread that will try to enter for write and
	 * check that it is blocked
	 */
	startConcurrentThread(info);
	ASSERT_TRUE(0 == info->writeCounter);

	/* now release the rwmutex and validate that the thread enters it */
	omrthread_monitor_enter(info->synchronization);
	omrthread_rwmutex_exit_write(info->handle);
	omrthread_monitor_wait_interruptable(info->synchronization, MILLI_TIMEOUT, NANO_TIMEOUT);
	omrthread_monitor_exit(info->synchronization);
	ASSERT_TRUE(1 == info->writeCounter);

	/* done now so ask thread to release and clean up */
	triggerNextStepDone(info);
	freeSupportThreadInfo(info);
}
/**
 * Discards a lock object.
 * An lock must be discarded to free the resources associated with it.
 * 
 * @note  A lock must not be destroyed if threads are waiting on it, or 
 * if it is currently owned.
 */
void
MM_LightweightNonReentrantLock::tearDown()
{
	if(NULL != _extensions) {
		if(NULL != _tracing) {
			if (NULL != _tracing->monitor_name) {
				_tracing->monitor_name = NULL;
			}

			J9Pool* tracingPool = _extensions->_lightweightNonReentrantLockPool;
			if(NULL != tracingPool) {
				omrthread_monitor_enter(_extensions->_lightweightNonReentrantLockPoolMutex);
				pool_removeElement(tracingPool, _tracing);
				omrthread_monitor_exit(_extensions->_lightweightNonReentrantLockPoolMutex);
			}
			_tracing = NULL;
		}
	}

	if (_initialized) {
#if defined(J9MODRON_USE_CUSTOM_SPINLOCKS)
		omrgc_spinlock_destroy(&_spinlock);
#else /* J9MODRON_USE_CUSTOM_SPINLOCKS */
		MUTEX_DESTROY(_mutex);
#endif /* J9MODRON_USE_CUSTOM_SPINLOCKS */
		_initialized = false;
	}
}
/**
 * Wait for expected event and optionally bring event related data back.
 *
 * @param testName The name of the waiting thread
 * @param info The pointer to SigMaskTestInfo object
 * @param event The expected event
 * @param result The event related data
 * @param size The size of the event data
 * @return TRUE upon success; FALSE if expected event did not occur before timeout.
 */
static BOOLEAN
waitForEvent(const char *testName, SigMaskTestInfo *info, SignalEvent event, void *result, size_t size)
{
	OMRPORT_ACCESS_FROM_OMRPORT(info->portLibrary);
	BOOLEAN ret = FALSE;
	intptr_t waitRC = J9THREAD_WOULD_BLOCK;

	omrthread_monitor_enter(info->monitor);

	while (info->bulletinBoard.event != event) {
		waitRC = omrthread_monitor_wait_timed(info->monitor, 60000, 0);
		if (J9THREAD_TIMED_OUT == waitRC) {
			break;
		}
	}

	ret = (info->bulletinBoard.event == event);
	if (TRUE == ret) {
		if ((NULL != result) && (size > 0)) {
			memcpy(result, &info->bulletinBoard.data, size);
		}
	} else {
		if (J9THREAD_TIMED_OUT == waitRC) {
			outputErrorMessage(PORTTEST_ERROR_ARGS, "timed out without being notified. expected (%d), received (%d)\n", event, info->bulletinBoard.event);
		} else {
			outputErrorMessage(PORTTEST_ERROR_ARGS, "expected event(%d) was not received. bulletinBoard(%d)\n", event, info->bulletinBoard.event);
		}
	}

	info->bulletinBoard.event = INVALID;

	omrthread_monitor_exit(info->monitor);

	return ret;
}
Beispiel #7
0
/*
 * Mark this event as disabled. Any future attempts to add a hook for this event
 * will result in an error.
 *
 * This function should not be called directly. It should be called through the hook interface
 *
 * Returns 0 on success, or non-zero if the event is already hooked or reserved
 */
static intptr_t
J9HookDisable(struct J9HookInterface **hookInterface, uintptr_t taggedEventNum)
{
	J9CommonHookInterface *commonInterface = (J9CommonHookInterface *)hookInterface;
	uintptr_t eventNum = taggedEventNum & J9HOOK_EVENT_NUM_MASK;

	/* try to answer without using the lock, first */
	if (HOOK_FLAGS(commonInterface, eventNum) & J9HOOK_FLAG_RESERVED) {
		return -1;
	} else if (HOOK_FLAGS(commonInterface, eventNum) & J9HOOK_FLAG_DISABLED) {
		return 0;
	} else {
		intptr_t rc = 0;

		omrthread_monitor_enter(commonInterface->lock);

		if (HOOK_FLAGS(commonInterface, eventNum) & (J9HOOK_FLAG_RESERVED | J9HOOK_FLAG_HOOKED)) {
			rc = -1;
		} else {
			HOOK_FLAGS(commonInterface, eventNum) |= J9HOOK_FLAG_DISABLED;
		}

		omrthread_monitor_exit(commonInterface->lock);

		return rc;
	}
}
Beispiel #8
0
static int
numaSetAffinitySuspendedThreadMain(void *arg)
{
	numadata_t *data = (numadata_t *)arg;
	omrthread_monitor_t monitor = data->monitor;

	uintptr_t status = 0;
	uintptr_t currentAffinity = 0;
	uintptr_t nodeCount = 1;

	J9THREAD_VERBOSE(omrthread_monitor_enter(monitor));
	if (0 != J9THREAD_VERBOSE(omrthread_numa_get_node_affinity(omrthread_self(), &currentAffinity, &nodeCount))) {
		status |= EXPECTED_VALID;
		goto endthread;
	}

	if (currentAffinity != data->expectedAffinity) {
		omrTestEnv->log(LEVEL_ERROR, "Affinity different from expected. Expected:%zu Actual:%zu\n", data->expectedAffinity, currentAffinity);
		status |= EXPECTED_VALID;
		goto endthread;
	}

endthread:
	data->status = status;
	J9THREAD_VERBOSE(omrthread_monitor_notify_all(monitor));
	J9THREAD_VERBOSE(omrthread_monitor_exit(monitor));
	return 0;
}
Beispiel #9
0
static omr_error_t
countTracepointsMT(UtSubscription *subscriptionID)
{
	TracePointCountsMT *tpCountsMT = (TracePointCountsMT *)subscriptionID->userData;
	const UtTraceRecord *traceRecord = (const UtTraceRecord *)subscriptionID->data;

	EXPECT_EQ(0, omrthread_monitor_enter(tpCountsMT->lock));
	TracePointCounts *tpCounts = NULL;
	for (int i = 0; i < tpCountsMT->numThreads; i += 1) {
		if ((omrthread_t)(uintptr_t)traceRecord->threadSyn1 == tpCountsMT->tpCounts[i].osThread) {
			tpCounts = &tpCountsMT->tpCounts[i];
			break;
		}
	}
	if (NULL == tpCounts) {
		for (int i = 0; i < tpCountsMT->numThreads; i += 1) {
			if (NULL == tpCountsMT->tpCounts[i].osThread) {
				tpCounts = &tpCountsMT->tpCounts[i];
				tpCounts->osThread = (omrthread_t)(uintptr_t)traceRecord->threadSyn1;
				break;
			}
		}
	}
	EXPECT_EQ(0, omrthread_monitor_exit(tpCountsMT->lock));

	EXPECT_TRUE(NULL != tpCounts);
	if (NULL != tpCounts) {
		processTraceRecord(&tpCounts->wrapBuffer, subscriptionID, countTracepointsIter, (void *)tpCounts);
	}
	return OMR_ERROR_NONE;
}
/**
 * Initialize a new lock object.
 * A lock must be initialized before it may be used.
 *
 * @param env
 * @param options
 * @param name Lock name
 * @return TRUE on success
 * @note Creates a store barrier.
 */
bool
MM_LightweightNonReentrantLock::initialize(MM_EnvironmentBase *env, ModronLnrlOptions *options, const char * name)
{
	OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());

	/* initialize variables in case constructor was not called */
	_initialized = false;
	_tracing = NULL;
	_extensions = env->getExtensions();

	if (NULL != _extensions) {
		J9Pool* tracingPool = _extensions->_lightweightNonReentrantLockPool;
		if (NULL != tracingPool) {
			omrthread_monitor_enter(_extensions->_lightweightNonReentrantLockPoolMutex);
			_tracing = (J9ThreadMonitorTracing *)pool_newElement(tracingPool);
			omrthread_monitor_exit(_extensions->_lightweightNonReentrantLockPoolMutex);

			if (NULL == _tracing) {
				goto error_no_memory;
			}
			_tracing->monitor_name = NULL;

			if (NULL != name) {
				uintptr_t length = omrstr_printf(NULL, 0, "[%p] %s", this, name) + 1;
				if (length > MAX_LWNR_LOCK_NAME_SIZE) {
					goto error_no_memory;
				}
				_tracing->monitor_name = _nameBuf;
				if (NULL == _tracing->monitor_name) {
					goto error_no_memory;
				}
				omrstr_printf(_tracing->monitor_name, length, "[%p] %s", this, name);
			}
		}
	}

#if defined(OMR_ENV_DATA64)
	if(0 != (((uintptr_t)this) % sizeof(uintptr_t))) {
		omrtty_printf("GC FATAL: LWNRL misaligned.\n");
		abort();
	}
#endif

#if defined(J9MODRON_USE_CUSTOM_SPINLOCKS)

	_initialized = omrgc_spinlock_init(&_spinlock) ? false : true;

	_spinlock.spinCount1 = options->spinCount1;
	_spinlock.spinCount2 = options->spinCount2;
	_spinlock.spinCount3 = options->spinCount3;
#else /* J9MODRON_USE_CUSTOM_SPINLOCKS */
	_initialized = MUTEX_INIT(_mutex) ? true : false;
#endif /* J9MODRON_USE_CUSTOM_SPINLOCKS */

	return _initialized;

error_no_memory:
	return false;
}
Beispiel #11
0
/*
 * Remove the specified function from the listeners for eventNum.
 * If userData is NULL, all functions matching function are removed.
 * If userData is non-NULL, only functions with matching userData are removed.
 *
 * This function should not be called directly. It should be called through the hook interface
 */
static void
J9HookUnregister(struct J9HookInterface **hookInterface, uintptr_t taggedEventNum, J9HookFunction function, void *userData)
{
	J9CommonHookInterface *commonInterface = (J9CommonHookInterface *)hookInterface;
	J9HookRecord *record;
	J9HookRegistrationEvent eventStruct;
	uintptr_t hooksRemaining = 0;
	uintptr_t hooksRemoved = 0;
	uintptr_t eventNum = taggedEventNum & J9HOOK_EVENT_NUM_MASK;

	eventStruct.eventNum = eventNum;
	eventStruct.function = function;
	eventStruct.isRegistration = 0;
	eventStruct.userData = NULL;
	eventStruct.agentID = J9HOOK_AGENTID_DEFAULT;

	omrthread_monitor_enter(commonInterface->lock);

	record = HOOK_RECORD(commonInterface, eventNum);
	while (record) {
		if (record->function == function) {
			if ((userData == NULL) || (record->userData == userData)) {
				if (taggedEventNum & J9HOOK_TAG_COUNTED) {
					if (--(record->count) != 0) {
						omrthread_monitor_exit(commonInterface->lock);
						return;
					}
				}

				if (userData != NULL) {
					/* copy data from the event record so that we can report it once we've released the mutex */
					eventStruct.userData = record->userData;
					eventStruct.agentID = record->agentID;
				}

				/* mark the record as invalid so that it can be recycled */
				record->id = HOOK_INVALID_ID(record->id);
				hooksRemoved++;
			}
		}
		if (HOOK_IS_VALID_ID(record->id)) {
			hooksRemaining++;
		}
		record = record->next;
	}

	if (hooksRemaining == 0) {
		HOOK_FLAGS(commonInterface, eventNum) &= ~J9HOOK_FLAG_HOOKED;
	}

	omrthread_monitor_exit(commonInterface->lock);

	if (hooksRemoved != 0) {
		/* report the unregistration event */
		(*hookInterface)->J9HookDispatch(hookInterface, J9HOOK_REGISTRATION_EVENT, &eventStruct);
	}
}
Beispiel #12
0
/**
 * This method is called to push the concurrent thread to run the next function
 */
void
triggerNextStepWithStatus(SupportThreadInfo *info, BOOLEAN done)
{
	omrthread_monitor_enter(info->synchronization);
	info->done = done;
	omrthread_monitor_notify(info->synchronization);
	omrthread_monitor_wait_interruptable(info->synchronization, MILLI_TIMEOUT, NANO_TIMEOUT);
	omrthread_monitor_exit(info->synchronization);
}
Beispiel #13
0
/**
 * Send a event and optionally event data to the waiting thread.
 *
 * @param info The pointer to SigMaskTestInfo object
 * @param event The event
 * @param value The pointer to event data
 * @param size The size of the event data
 */
static void
sendEvent(SigMaskTestInfo *info, SignalEvent event, void *value, size_t size)
{
	omrthread_monitor_enter(info->monitor);
	info->bulletinBoard.event = event;
	if ((NULL != value) && (size > 0)) {
		memcpy(&info->bulletinBoard.data, value, size);
	}
	omrthread_monitor_notify(info->monitor);
	omrthread_monitor_exit(info->monitor);
}
Beispiel #14
0
intptr_t
sem_post_zos(j9sem_t s)
{
	zos_sem_t *zs = (zos_sem_t *) s;

	omrthread_monitor_enter(zs->monitor);
	zs->count++;
	omrthread_monitor_notify(zs->monitor);
	omrthread_monitor_exit(zs->monitor);

	return 0;
}
Beispiel #15
0
TEST_F(ThreadCreateTest, NumaSetAffinity)
{
	uintptr_t status = 0;
	omrthread_t thread;
	omrthread_monitor_t monitor;
	numadata_t data;
	uintptr_t nodeCount = 0;
	intptr_t affinityResultCode = 0;

	if (0 != J9THREAD_VERBOSE(omrthread_monitor_init(&monitor, 0))) {
		omrTestEnv->log(LEVEL_ERROR, "Failed to initialize monitor\n");
		status |= NULL_ATTR;
		goto endtest;
	}

	data.monitor = monitor;
	data.status = 0;
	data.expectedAffinity = 0;

	omrthread_monitor_enter(monitor);

	nodeCount = 1;
	affinityResultCode = omrthread_numa_get_node_affinity(omrthread_self(), &data.expectedAffinity, &nodeCount);
	if (J9THREAD_NUMA_ERR_AFFINITY_NOT_SUPPORTED == affinityResultCode) {
		/* this platform can't meaningfully run this test so just end */
		omrTestEnv->log(LEVEL_ERROR, "NUMA-level thread affinity not supported on this platform\n");
		goto endtest;
	}
	if (J9THREAD_NUMA_OK != affinityResultCode) {
		omrTestEnv->log(LEVEL_ERROR, "Failed to get parent thread's affinity\n");
		status |= CREATE_FAILED;
		goto endtest;
	}

	if (J9THREAD_SUCCESS != J9THREAD_VERBOSE(omrthread_create_ex(&thread, J9THREAD_ATTR_DEFAULT, 0, numaSetAffinityThreadMain, &data))) {
		omrTestEnv->log(LEVEL_ERROR, "Failed to create the thread\n");
		status |= CREATE_FAILED;
		goto endtest;
	}

	if (0 != omrthread_monitor_wait(monitor)) {
		omrTestEnv->log(LEVEL_ERROR, "Failed to wait on monitor\n");
		status |= NULL_ATTR;
		goto endtest;
	}

	status |= data.status;
endtest:
	omrthread_monitor_exit(monitor);
	omrthread_monitor_destroy(monitor);
	ASSERT_EQ((uintptr_t)0, status) << "Failed with Code: " << std::hex << status;
}
Beispiel #16
0
bool
MM_MasterGCThread::handleConcurrent(MM_EnvironmentBase *env)
{
	bool workDone = false;

	_masterThreadState = STATE_RUNNING_CONCURRENT;

	if (_acquireVMAccessDuringConcurrent) {
		omrthread_monitor_exit(_collectorControlMutex);
		env->acquireVMAccess();
	}
	if (_collector->isConcurrentWorkAvailable(env)) {
		MM_ConcurrentPhaseStatsBase *stats = _collector->getConcurrentPhaseStats();

		_collector->preConcurrentInitializeStatsAndReport(env, stats);
		if (!_acquireVMAccessDuringConcurrent) {
			omrthread_monitor_exit(_collectorControlMutex);
		}
		uintptr_t bytesConcurrentlyScanned = _collector->masterThreadConcurrentCollect(env);

		if (!_acquireVMAccessDuringConcurrent) {
			omrthread_monitor_enter(_collectorControlMutex);
		}

		_collector->postConcurrentUpdateStatsAndReport(env, stats, bytesConcurrentlyScanned);
		workDone = true;
	}

	if (_acquireVMAccessDuringConcurrent) {
		env->releaseVMAccess();
		omrthread_monitor_enter(_collectorControlMutex);
	}

	if (STATE_RUNNING_CONCURRENT == _masterThreadState) {
		_masterThreadState = STATE_WAITING;
	}

	return workDone;
}
Beispiel #17
0
/**
 * @return a new unique identifier for a hookable agent, or 0 on failure
 *
 * This function should not be called directly. It should be called through the hook interface
 */
static uintptr_t
J9HookAllocateAgentID(struct J9HookInterface **hookInterface)
{
	J9CommonHookInterface *commonInterface = (J9CommonHookInterface *)hookInterface;
	uintptr_t id = 0;

	omrthread_monitor_enter(commonInterface->lock);
	if (commonInterface->nextAgentID < J9HOOK_AGENTID_LAST) {
		id = commonInterface->nextAgentID++;
	}
	omrthread_monitor_exit(commonInterface->lock);

	return id;
}
Beispiel #18
0
/**
 * This method is called to run the set of steps that will be run on a thread
 * @param info SupportThreadInfo structure that contains the information for the steps and other parameters
 *        that are used
 */
static intptr_t J9THREAD_PROC
runRequest(SupportThreadInfo *info)
{
	intptr_t result = 0;
	uintptr_t i = 0;

	omrthread_monitor_enter(info->synchronization);
	omrthread_monitor_exit(info->synchronization);
	for (i = 0; i < info->numberFunctions; i++) {
		result = info->functionsToRun[i]((void *)info);
		omrthread_monitor_enter(info->synchronization);
		omrthread_monitor_notify(info->synchronization);
		if (info->done == TRUE) {
			omrthread_monitor_exit(info->synchronization);
			break;
		}
		omrthread_monitor_wait_interruptable(info->synchronization,
											STEP_MILLI_TIMEOUT, STEP_NANO_TIMEOUT);
		omrthread_monitor_exit(info->synchronization);
	}

	return result;
}
Beispiel #19
0
intptr_t
sem_wait_zos(j9sem_t s)
{
	zos_sem_t *zs = (zos_sem_t *) s;

	omrthread_monitor_enter(zs->monitor);
	while (zs->count == 0) {
		omrthread_monitor_wait(zs->monitor);
	}
	zs->count--;
	omrthread_monitor_exit(zs->monitor);

	return 0;
}
Beispiel #20
0
intptr_t
sem_trywait_zos(j9sem_t s)
{
	uintptr_t rval = -1;
	zos_sem_t *zs = (zos_sem_t *) s;

	omrthread_monitor_enter(zs->monitor);
	if (zs->count > 0) {
		-- zs->count;
		rval =  zs->count;
	}
	omrthread_monitor_exit(zs->monitor);

	return rval;
}
Beispiel #21
0
/*
 * Inform all registered listeners that the specified event has occurred. Details about the
 * event should be available through eventData.
 *
 * If the J9HOOK_TAG_ONCE bit is set in the taggedEventNum, then the event is disabled
 * before the listeners are informed. Any attempts to add listeners to a TAG_ONCE event
 * once it has been reported will fail.
 *
 * This function should not be called directly. It should be called through the hook interface
 *
 */
static void
J9HookDispatch(struct J9HookInterface **hookInterface, uintptr_t taggedEventNum, void *eventData)
{
	uintptr_t eventNum = taggedEventNum & J9HOOK_EVENT_NUM_MASK;
	J9CommonHookInterface *commonInterface = (J9CommonHookInterface *)hookInterface;
	J9HookRecord *record = HOOK_RECORD(commonInterface, eventNum);

	if (taggedEventNum & J9HOOK_TAG_ONCE) {
		uint8_t oldFlags;

		omrthread_monitor_enter(commonInterface->lock);
		oldFlags = HOOK_FLAGS(commonInterface, eventNum);
		/* clear the HOOKED and RESERVED flags and set the DISABLED flag */
		HOOK_FLAGS(commonInterface, eventNum) = (oldFlags | J9HOOK_FLAG_DISABLED) & ~(J9HOOK_FLAG_RESERVED | J9HOOK_FLAG_HOOKED);
		omrthread_monitor_exit(commonInterface->lock);

		if (oldFlags & J9HOOK_FLAG_DISABLED) {
			/* already reported */
			return;
		}
	}

	while (record) {
		J9HookFunction function;
		void *userData;
		uintptr_t id;

		/* ensure that the id is read before any other fields */
		id = record->id;
		if (HOOK_IS_VALID_ID(id)) {
			VM_AtomicSupport::readBarrier();

			function = record->function;
			userData = record->userData;

			/* now read the id again to make sure that nothing has changed */
			VM_AtomicSupport::readBarrier();
			if (record->id == id) {
				function(hookInterface, eventNum, eventData, userData);
			} else {
				/* this record has been updated while we were reading it. Skip it. */
			}
		}

		record = record->next;
	}
}
Beispiel #22
0
void
MM_MasterGCThread::shutdown()
{
	Assert_MM_true(NULL != _collectorControlMutex);
	if ((STATE_ERROR != _masterThreadState) && (STATE_DISABLED != _masterThreadState)) {
		/* tell the background thread to shut down and then wait for it to exit */
		omrthread_monitor_enter(_collectorControlMutex);
		while(STATE_TERMINATED != _masterThreadState) {
			_masterThreadState = STATE_TERMINATION_REQUESTED;
			omrthread_monitor_notify(_collectorControlMutex);
			omrthread_monitor_wait(_collectorControlMutex);
		}
		omrthread_monitor_exit(_collectorControlMutex);
		
		/* don't NULL _collector as RAS could still trigger a collection after we've started shutting down */
	}
}
Beispiel #23
0
/**
 * Request to create sweepPoolState class for pool
 * @param  memoryPool memory pool to attach sweep state to
 * @return pointer to created class
 */
void *
MM_ParallelSweepScheme::createSweepPoolState(MM_EnvironmentBase *env, MM_MemoryPool *memoryPool)
{
	OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());

	omrthread_monitor_enter(_mutexSweepPoolState);
	if (NULL == _poolSweepPoolState) {
		_poolSweepPoolState = pool_new(sizeof(MM_SweepPoolState), 0, 2 * sizeof(uintptr_t), 0, OMR_GET_CALLSITE(), OMRMEM_CATEGORY_MM, POOL_FOR_PORT(OMRPORTLIB));
		if (NULL == _poolSweepPoolState) {
			omrthread_monitor_exit(_mutexSweepPoolState);
			return NULL;
		}
	}
	omrthread_monitor_exit(_mutexSweepPoolState);
	
	return MM_SweepPoolState::newInstance(env, _poolSweepPoolState, _mutexSweepPoolState, memoryPool);
}
Beispiel #24
0
/**
 * This method starts a concurrent thread and runs the functions specified in the
 * SupportThreadInfo passed in.  It only returns once the first function has run
 *
 * @param info SupporThreadInfo structure containing the functions and rwmutex for the tests
 * @returns 0 on success
 */
intptr_t
startConcurrentThread(SupportThreadInfo *info)
{
	omrthread_t newThread = NULL;

	omrthread_monitor_enter(info->synchronization);
	omrthread_create_ex(
		&newThread,
		J9THREAD_ATTR_DEFAULT, /* default attr */
		0, /* start immediately */
		(omrthread_entrypoint_t) runRequest,
		(void *)info);

	omrthread_monitor_wait_interruptable(info->synchronization, MILLI_TIMEOUT, NANO_TIMEOUT);
	omrthread_monitor_exit(info->synchronization);

	return 0;
}
Beispiel #25
0
static omr_error_t
waitForTestChildThread(OMRTestVM *testVM, omrthread_t childThead, TestChildThreadData *childData)
{
	omr_error_t childRc = OMR_ERROR_NONE;
	OMRPORT_ACCESS_FROM_OMRPORT(testVM->portLibrary);

	omrthread_monitor_enter(childData->shutdownCond);
	while (!childData->isDead) {
		omrthread_monitor_wait(childData->shutdownCond);
	}
	omrthread_monitor_exit(childData->shutdownCond);

	childRc = childData->childRc;

	omrthread_monitor_destroy(childData->shutdownCond);
	omrmem_free_memory(childData);
	return childRc;
}
Beispiel #26
0
void
MM_EnvironmentBase::releaseExclusiveForConcurrentKickoff()
{
	MM_GCExtensionsBase *extensions = MM_GCExtensionsBase::getExtensions(_omrVM);

	Assert_MM_true(extensions->gcExclusiveAccessThreadId ==_omrVMThread );
	Assert_MM_true(0 != _exclusiveCount);

	_exclusiveCount -= 1;
	if (0 == _exclusiveCount) {
		omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
		extensions->gcExclusiveAccessThreadId = NULL;
		omrthread_monitor_notify_all(extensions->gcExclusiveAccessMutex);
		omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);

		reportExclusiveAccessRelease();
		_envLanguageInterface->releaseExclusiveVMAccess();
	}
}
Beispiel #27
0
void
MM_EnvironmentBase::releaseExclusiveVMAccessForGC()
{
	MM_GCExtensionsBase *extensions = MM_GCExtensionsBase::getExtensions(_omrVM);

	Assert_MM_true(extensions->gcExclusiveAccessThreadId == _omrVMThread);
	Assert_MM_true(0 != _exclusiveCount);

	_exclusiveCount -= 1;
	if (0 == _exclusiveCount) {
		omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
		extensions->gcExclusiveAccessThreadId = _cachedGCExclusiveAccessThreadId;
		_cachedGCExclusiveAccessThreadId = NULL;
		omrthread_monitor_notify_all(extensions->gcExclusiveAccessMutex);
		omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);
		reportExclusiveAccessRelease();
		_delegate.releaseExclusiveVMAccess();
	}
}
Beispiel #28
0
/*
 * Use J9HookReserve to indicate your intention to hook an event in the future.
 * Certain events must be reserved before the providing module initializes completely,
 * or it may make decisions which make it impossible to add the hooks later.
 * Once the point of no-return is reached, the providing module will disable the
 * event if it has not been registered or reserved.
 *
 * This function should not be called directly. It should be called through the hook interface
 *
 * returns 0 on success
 * non-zero if the event has been disabled
 */
static intptr_t
J9HookReserve(struct J9HookInterface **hookInterface, uintptr_t taggedEventNum)
{
	J9CommonHookInterface *commonInterface = (J9CommonHookInterface *)hookInterface;
	intptr_t rc = 0;
	uintptr_t eventNum = taggedEventNum & J9HOOK_EVENT_NUM_MASK;

	omrthread_monitor_enter(commonInterface->lock);

	if (HOOK_FLAGS(commonInterface, eventNum) & J9HOOK_FLAG_DISABLED) {
		rc = -1;
	} else {
		HOOK_FLAGS(commonInterface, eventNum) |= J9HOOK_FLAG_RESERVED;
	}

	omrthread_monitor_exit(commonInterface->lock);

	return rc;
}
Beispiel #29
0
void
MM_EnvironmentBase::unwindExclusiveVMAccessForGC()
{
	MM_GCExtensionsBase *extensions = MM_GCExtensionsBase::getExtensions(_omrVM);

	if(_exclusiveCount > 0) {
		Assert_MM_true(extensions->gcExclusiveAccessThreadId == _omrVMThread);

		_exclusiveCount = 0;

		omrthread_monitor_enter(extensions->gcExclusiveAccessMutex);
		extensions->gcExclusiveAccessThreadId = NULL;
		omrthread_monitor_notify_all(extensions->gcExclusiveAccessMutex);
		omrthread_monitor_exit(extensions->gcExclusiveAccessMutex);

		reportExclusiveAccessRelease();

		_envLanguageInterface->releaseExclusiveVMAccess();
	}
}
Beispiel #30
0
bool
MM_MasterGCThread::startup()
{
	/* set the success flag to false and we will set it true if everything succeeds */
	bool success = false;

	if (_extensions->fvtest_disableExplictMasterThread) {
		/* GC should be able to act even if master thread is not created (or late) */
		_masterThreadState = STATE_DISABLED;
		success = true;
	} else {
		/* hold the monitor over start-up of this thread so that we eliminate any timing hole where it might notify us of its start-up state before we wait */
		omrthread_monitor_enter(_collectorControlMutex);
		_masterThreadState = STATE_STARTING;
		intptr_t forkResult = createThreadWithCategory(
			NULL,
			OMR_OS_STACK_SIZE,
			J9THREAD_PRIORITY_NORMAL,
			0,
			master_thread_proc,
			this,
			J9THREAD_CATEGORY_SYSTEM_GC_THREAD);
		if (forkResult == 0) {
			/* thread creation success */
			/* wait to find out if they started up, successfully */
			while (STATE_STARTING == _masterThreadState) {
				omrthread_monitor_wait(_collectorControlMutex);
			}
			if (STATE_ERROR != _masterThreadState) {
				/* the master thread managed to start up and is in the waiting state, ready for GC requests */
				success = true;
			}
		} else {
			_masterThreadState = STATE_ERROR;
		}
		omrthread_monitor_exit(_collectorControlMutex);
	}

	return success;
}