Path: blob/master/runtime/gc_realtime/MetronomeAlarm.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2019 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "EnvironmentBase.hpp"23#include "MetronomeAlarmThread.hpp"24#include "OSInterface.hpp"25#include "Scheduler.hpp"2627#include "MetronomeAlarm.hpp"2829#if defined(LINUX)30#include <time.h>31#include <errno.h>32#include <sys/time.h>33#include <sys/mman.h>34#include <sched.h>35#include <unistd.h>36#include <sys/types.h>37#include <sys/stat.h>38#include <fcntl.h>39#include <sys/ioctl.h>40#include <netdb.h>41#include <sys/socket.h>42#include <sys/types.h>43#include <net/if.h>44#include <netdb.h>45#include <netinet/in.h>46#include <arpa/inet.h>47#endif /* #if defined(LINUX) */48#if defined(LINUX) && !defined(J9ZTPF)49#include <linux/rtc.h>50#include <sys/syscall.h>51#include <sys/signal.h>52#elif defined(J9ZTPF)53#include <signal.h>54#endif /* defined(LINUX) && !defined(J9ZTPF) */5556MM_HRTAlarm *57MM_HRTAlarm::newInstance(MM_EnvironmentBase *env)58{59MM_HRTAlarm * alarm;6061alarm = (MM_HRTAlarm *)env->getForge()->allocate(sizeof(MM_HRTAlarm), MM_AllocationCategory::FIXED, OMR_GET_CALLSITE());62if (alarm) {63new(alarm) MM_HRTAlarm();64}65return alarm;66}6768MM_RTCAlarm *69MM_RTCAlarm::newInstance(MM_EnvironmentBase *env)70{71MM_RTCAlarm * alarm;7273alarm = (MM_RTCAlarm *)env->getForge()->allocate(sizeof(MM_RTCAlarm), MM_AllocationCategory::FIXED, OMR_GET_CALLSITE());74if (alarm) {75new(alarm) MM_RTCAlarm();76}77return alarm;78}7980MM_ITAlarm *81MM_ITAlarm::newInstance(MM_EnvironmentBase *env)82{83MM_ITAlarm * alarm;8485alarm = (MM_ITAlarm *)env->getForge()->allocate(sizeof(MM_ITAlarm), MM_AllocationCategory::FIXED, OMR_GET_CALLSITE());86if (alarm) {87new(alarm) MM_ITAlarm();88}89return alarm;90}9192/**93* MM_Alarm::newInstance - create a new alarm suitable for the system.94*/95MM_Alarm*96MM_Alarm::factory(MM_EnvironmentBase *env, MM_OSInterface* osInterface)97{98MM_Alarm *alarm = NULL;99100if (osInterface->hiresTimerAvailable()) {101alarm = MM_HRTAlarm::newInstance(env);102} else if (osInterface->itTimerAvailable()) {103alarm = MM_ITAlarm::newInstance(env);104}105return alarm;106}107108109/**110* initialize111* Initialize the High Resolution Timer for use by Metronome.112* @return true if the high resolution timer was successfully initialized, false113* otherwise114*/115bool116MM_HRTAlarm::initialize(MM_EnvironmentBase *env, MM_MetronomeAlarmThread* alarmThread)117{118_extensions = MM_GCExtensionsBase::getExtensions(env->getOmrVM());119return alarmThread->startThread(env);120}121122/**123* initialize124* Initialize the Linux real-time clock for use by Metronome. On125* non-Linux OS's, it is an error to be working with RTCAlarm's126* This code has OS-specific code in it, but it will disappear in time127* when we have HRT Alarm's running everywhere...128* @return true if the real-time clock was successfully initialized, false129* otherwise130*/131132bool133MM_RTCAlarm::initialize(MM_EnvironmentBase *env, MM_MetronomeAlarmThread* alarmThread)134{135_extensions = MM_GCExtensionsBase::getExtensions(env->getOmrVM());136#if defined(LINUX) && !defined(J9ZTPF)137OMRPORT_ACCESS_FROM_ENVIRONMENT(env);138139RTCfd = open("/dev/rtc", O_RDONLY);140if (RTCfd == -1) {141if (_extensions->verbose >= 2) {142omrtty_printf("Unable to open /dev/rtc\n");143}144goto error;145}146if ((ioctl(RTCfd, RTC_IRQP_SET, _extensions->RTC_Frequency) == -1)) {147if (_extensions->verbose >= 2) {148omrtty_printf("Unable to set IRQP for /dev/rtc\n");149}150goto error;151}152if (ioctl(RTCfd, RTC_IRQP_READ, &_extensions->RTC_Frequency)) {153if (_extensions->verbose >= 2) {154omrtty_printf("Unable to read IRQP for /dev/rtc\n");155}156goto error;157}158if (ioctl(RTCfd, RTC_PIE_ON, 0) == -1) {159if (_extensions->verbose >= 2) {160omrtty_printf("Unable to enable PIE for /dev/rtc\n");161}162goto error;163}164165return alarmThread->startThread(env);166167error:168if (_extensions->verbose >= 1) {169omrtty_printf("Unable to use /dev/rtc for time-based scheduling\n");170}171return false;172#else173return false;174#endif /* defined(LINUX) && !defined(J9ZTPF) */175}176177void MM_ITAlarm::alarm_handler(MM_MetronomeAlarmThread *alarmThread) {178MM_Scheduler *sched = alarmThread->getScheduler();179sched->_osInterface->maskSignals();180omrthread_resume(alarmThread->_thread);181}182183#if defined(WIN32)184static void CALLBACK185itAlarmThunk(PVOID lpParam, BOOLEAN timerOrWaitFired)186{187MM_ITAlarm::alarm_handler((MM_MetronomeAlarmThread *)lpParam);188}189#endif /*WIN32*/190191192/**193* Initialize the interval timer alarm. This timer is not194* used except as a backup if HRT and RTC alarms aren't available.195* This code has OS-specific code in it, but it will disappear in time196* when we have HRT Alarm's running everywhere...197* @return true if the real-time clock was successfully initialized, false198* otherwise199*/200bool201MM_ITAlarm::initialize(MM_EnvironmentBase *env, MM_MetronomeAlarmThread* alarmThread)202{203_extensions = MM_GCExtensionsBase::getExtensions(env->getOmrVM());204if (!alarmThread->startThread(env)) {205return false;206}207208#if defined(WIN32)209DWORD dwPeriod = (DWORD)(_extensions->itPeriodMicro / 1000);210DWORD dwDelay = dwPeriod;211BOOL ret = CreateTimerQueueTimer(&_hTimer, NULL, (WAITORTIMERCALLBACK)itAlarmThunk, (PVOID)alarmThread, dwDelay, dwPeriod, 0);212if (!ret) {213/* Error creating timer */214_hTimer = NULL;215return false;216}217218return true;219#else /* !defined(WIN32)*/220/* write code if we want this path on other platforms */221return false;222#endif /* defined(WIN32) */223}224225void226MM_RTCAlarm::sleep()227{228#if defined(LINUX) && !defined(J9ZTPF)229uintptr_t data;230ssize_t readAmount = read(RTCfd, &data, sizeof(data));231if (readAmount == -1) {232perror("blocking read failed");233}234#endif /* defined(LINUX) && !defined(J9ZTPF) */235}236237void238MM_HRTAlarm::sleep()239{240omrthread_nanosleep(_extensions->hrtPeriodMicro * 1000);241}242243void244MM_ITAlarm::sleep()245{246omrthread_suspend();247}248249void MM_RTCAlarm::describe(OMRPortLibrary* port, char *buffer, I_32 bufferSize) {250OMRPORT_ACCESS_FROM_OMRPORT(port);251omrstr_printf(buffer, bufferSize, "RTC (Period = %.2f us Frequency = %d Hz)", 1.0/_extensions->RTC_Frequency, _extensions->RTC_Frequency);252}253254void MM_HRTAlarm::describe(OMRPortLibrary* port, char *buffer, I_32 bufferSize) {255OMRPORT_ACCESS_FROM_OMRPORT(port);256omrstr_printf(buffer, bufferSize, "High Resolution Timer (Period = %d us)", _extensions->hrtPeriodMicro);257}258259void MM_ITAlarm::describe(OMRPortLibrary* port, char *buffer, I_32 bufferSize) {260OMRPORT_ACCESS_FROM_OMRPORT(port);261omrstr_printf(buffer, bufferSize, "Interval Timer (Period = %d us)", _extensions->itPeriodMicro);262}263264/**265* kill266* teardown the environment and free up storage associated with the object267*/268void269MM_Alarm::kill(MM_EnvironmentBase *env)270{271tearDown(env);272env->getForge()->free(this);273}274275/**276* tearDown277*/278void279MM_Alarm::tearDown(MM_EnvironmentBase *env)280{281}282283/**284* tearDown285*/286void287MM_ITAlarm::tearDown(MM_EnvironmentBase *env)288{289#if defined(WIN32)290if (NULL != _hTimer) {291DeleteTimerQueueTimer(NULL, _hTimer, NULL);292}293#endif /* defined(WIN32) */294MM_Alarm::tearDown(env);295}296297298