Files
openthread/tests/unit/test_platform.cpp
T
Abtin Keshavarzian bbab3074ed [instance] single OpenThread instance optimizations (#1926)
This commit new configuration option `enable-multiple-instances` and
its corresponding option `OPENTHREAD_ENABLE_MULTIPLE_INSTANCES`. When
enabled OpenThread supports handling of multiple instances. By default
this is disabled.

This commit also adds two optimizations for single instance case to
simplify the code and also help reduce memory/RAM usage:

(1) OpenThread objects/classes typically keep a reference to a higher
level object (e.g., many classes keep track of owning `ThreadNetif`)
to be able to access other objects/methods within OpenThread class
hierarchy. In single instance mode, the reference member variables are
removed and instead global functions are used to access the singleton
objects from one class to the other. To implement this, a group of
`<Object>Locator` classes are defined (e.g., `ThreadNetifLocator`,
etc.) which are then used as base class of other OpenThread classes.

(2) OpenThread objects which provide a callback/handler (e.g.,
`Timer`, `Tasklet`, etc.) have `void *mContext` member variable which
is used to keep track of the owner of the object. In single instance
mode the `mConext` member variables are removed since the owner is
expected to be a singleton and can be uniquely determined from the
callback function.

To implement this, two changes are made: First the handler methods are
modified to provide a reference to the object (e.g., `Timer` handler
will provide a `Timer &aTimer` as a parameter of its handler
callback). Second, a new base class `Context` is introduced which
hides the implementation providing an arbitrary context information. A
new static method `GetOwner(aContext)` is added to classes which own a
callback providing objects. This method help convert a `Context` to
the reference of the owner class object.
2017-06-30 11:48:26 -07:00

536 lines
13 KiB
C++

/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_platform.h"
#if _WIN32
__forceinline int gettimeofday(struct timeval *tv, struct timezone *)
{
DWORD tick = GetTickCount();
tv->tv_sec = (long)(tick / 1000);
tv->tv_usec = (long)(tick * 1000);
return 0;
}
#else
#include <sys/time.h>
#endif
bool g_testPlatAlarmSet = false;
uint32_t g_testPlatAlarmNext = 0;
testPlatAlarmStop g_testPlatAlarmStop = NULL;
testPlatAlarmStartAt g_testPlatAlarmStartAt = NULL;
testPlatAlarmGetNow g_testPlatAlarmGetNow = NULL;
otRadioCaps g_testPlatRadioCaps = OT_RADIO_CAPS_NONE;
testPlatRadioSetPanId g_testPlatRadioSetPanId = NULL;
testPlatRadioSetExtendedAddress g_testPlatRadioSetExtendedAddress = NULL;
testPlatRadioIsEnabled g_testPlatRadioIsEnabled = NULL;
testPlatRadioEnable g_testPlatRadioEnable = NULL;
testPlatRadioDisable g_testPlatRadioDisable = NULL;
testPlatRadioSetShortAddress g_testPlatRadioSetShortAddress = NULL;
testPlatRadioReceive g_testPlatRadioReceive = NULL;
testPlatRadioTransmit g_testPlatRadioTransmit = NULL;
testPlatRadioGetTransmitBuffer g_testPlatRadioGetTransmitBuffer = NULL;
void testPlatResetToDefaults(void)
{
g_testPlatAlarmSet = false;
g_testPlatAlarmNext = 0;
g_testPlatAlarmStop = NULL;
g_testPlatAlarmStartAt = NULL;
g_testPlatAlarmGetNow = NULL;
g_testPlatRadioCaps = OT_RADIO_CAPS_NONE;
g_testPlatRadioSetPanId = NULL;
g_testPlatRadioSetExtendedAddress = NULL;
g_testPlatRadioSetShortAddress = NULL;
g_testPlatRadioIsEnabled = NULL;
g_testPlatRadioEnable = NULL;
g_testPlatRadioDisable = NULL;
g_testPlatRadioReceive = NULL;
g_testPlatRadioTransmit = NULL;
g_testPlatRadioGetTransmitBuffer = NULL;
}
otInstance *testInitInstance(void)
{
otInstance *instance = NULL;
#if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
size_t instaneBufferLength = 0;
uint8_t *instanceBuffer = NULL;
// Call to query the buffer size
(void)otInstanceInit(NULL, &instaneBufferLength);
// Call to allocate the buffer
instanceBuffer = (uint8_t *)malloc(instaneBufferLength);
VerifyOrQuit(instanceBuffer != NULL, "Failed to allocate otInstance");
memset(instanceBuffer, 0, instaneBufferLength);
// Initialize OpenThread with the buffer
instance = otInstanceInit(instanceBuffer, &instaneBufferLength);
#else
instance = otInstanceInitSingle();
#endif
return instance;
}
void testFreeInstance(otInstance *aInstance)
{
otInstanceFinalize(aInstance);
#if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
free(aInstance);
#endif
}
bool sDiagMode = false;
extern "C" {
#if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
void *otPlatCAlloc(size_t aNum, size_t aSize)
{
return calloc(aNum, aSize);
}
void otPlatFree(void *aPtr)
{
free(aPtr);
}
#endif
void otTaskletsSignalPending(otInstance *)
{
}
//
// Alarm
//
void otPlatAlarmStop(otInstance *aInstance)
{
if (g_testPlatAlarmStop)
{
g_testPlatAlarmStop(aInstance);
}
else
{
g_testPlatAlarmSet = false;
}
}
void otPlatAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
{
if (g_testPlatAlarmStartAt)
{
g_testPlatAlarmStartAt(aInstance, aT0, aDt);
}
else
{
g_testPlatAlarmSet = true;
g_testPlatAlarmNext = aT0 + aDt;
}
}
uint32_t otPlatAlarmGetNow(void)
{
if (g_testPlatAlarmGetNow)
{
return g_testPlatAlarmGetNow();
}
else
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint32_t)((tv.tv_sec * 1000) + (tv.tv_usec / 1000) + 123456);
}
}
//
// Radio
//
void otPlatRadioGetIeeeEui64(otInstance *, uint8_t *)
{
}
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
{
if (g_testPlatRadioSetPanId)
{
g_testPlatRadioSetPanId(aInstance, aPanId);
}
}
void otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *aExtAddr)
{
if (g_testPlatRadioSetExtendedAddress)
{
g_testPlatRadioSetExtendedAddress(aInstance, aExtAddr);
}
}
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddr)
{
if (g_testPlatRadioSetShortAddress)
{
g_testPlatRadioSetShortAddress(aInstance, aShortAddr);
}
}
void otPlatRadioSetPromiscuous(otInstance *, bool)
{
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
if (g_testPlatRadioIsEnabled)
{
return g_testPlatRadioIsEnabled(aInstance);
}
else
{
return true;
}
}
otError otPlatRadioEnable(otInstance *aInstance)
{
if (g_testPlatRadioEnable)
{
return g_testPlatRadioEnable(aInstance);
}
else
{
return OT_ERROR_NONE;
}
}
otError otPlatRadioDisable(otInstance *aInstance)
{
if (g_testPlatRadioEnable)
{
return g_testPlatRadioDisable(aInstance);
}
else
{
return OT_ERROR_NONE;
}
}
otError otPlatRadioSleep(otInstance *)
{
return OT_ERROR_NONE;
}
otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
if (g_testPlatRadioReceive)
{
return g_testPlatRadioReceive(aInstance, aChannel);
}
else
{
return OT_ERROR_NONE;
}
}
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
{
(void)aFrame;
if (g_testPlatRadioTransmit)
{
return g_testPlatRadioTransmit(aInstance);
}
else
{
return OT_ERROR_NONE;
}
}
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
{
if (g_testPlatRadioGetTransmitBuffer)
{
return g_testPlatRadioGetTransmitBuffer(aInstance);
}
else
{
return (otRadioFrame *)0;
}
}
int8_t otPlatRadioGetRssi(otInstance *)
{
return 0;
}
otRadioCaps otPlatRadioGetCaps(otInstance *)
{
return g_testPlatRadioCaps;
}
bool otPlatRadioGetPromiscuous(otInstance *)
{
return false;
}
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
{
(void)aInstance;
(void)aEnable;
}
otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
(void)aInstance;
(void)aShortAddress;
return OT_ERROR_NONE;
}
otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
(void)aInstance;
(void)aExtAddress;
return OT_ERROR_NONE;
}
otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
(void)aInstance;
(void)aShortAddress;
return OT_ERROR_NONE;
}
otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
(void)aInstance;
(void)aExtAddress;
return OT_ERROR_NONE;
}
void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
{
(void)aInstance;
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
{
(void)aInstance;
}
otError otPlatRadioEnergyScan(otInstance *, uint8_t, uint16_t)
{
return OT_ERROR_NOT_IMPLEMENTED;
}
void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
(void)aPower;
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
(void)aInstance;
return 0;
}
//
// Random
//
uint32_t otPlatRandomGet(void)
{
#if _WIN32
return (uint32_t)rand();
#else
return (uint32_t)random();
#endif
}
otError otPlatRandomGetTrue(uint8_t *aOutput, uint16_t aOutputLength)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(aOutput, error = OT_ERROR_INVALID_ARGS);
for (uint16_t length = 0; length < aOutputLength; length++)
{
aOutput[length] = (uint8_t)otPlatRandomGet();
}
exit:
return error;
}
//
// Diag
//
void otPlatDiagProcess(int argc, char *argv[], char *aOutput)
{
// no more diagnostics features for Posix platform
sprintf(aOutput, "diag feature '%s' is not supported\r\n", argv[0]);
(void)argc;
}
void otPlatDiagModeSet(bool aMode)
{
sDiagMode = aMode;
}
bool otPlatDiagModeGet()
{
return sDiagMode;
}
void otPlatDiagAlarmFired(otInstance *)
{
}
void otPlatDiagRadioTransmitDone(otInstance *, otRadioFrame *, otError)
{
}
void otPlatDiagRadioReceiveDone(otInstance *, otRadioFrame *, otError)
{
}
//
// Uart
//
void otPlatUartSendDone(void)
{
}
void otPlatUartReceived(const uint8_t *, uint16_t)
{
}
//
// Misc
//
void otPlatReset(otInstance *aInstance)
{
(void)aInstance;
}
otPlatResetReason otPlatGetResetReason(otInstance *aInstance)
{
(void)aInstance;
return OT_PLAT_RESET_REASON_POWER_ON;
}
void otPlatLog(otLogLevel, otLogRegion, const char *, ...)
{
}
//
// Settings
//
void otPlatSettingsInit(otInstance *aInstance)
{
(void)aInstance;
}
otError otPlatSettingsBeginChange(otInstance *aInstance)
{
(void)aInstance;
return OT_ERROR_NONE;
}
otError otPlatSettingsCommitChange(otInstance *aInstance)
{
(void)aInstance;
return OT_ERROR_NONE;
}
otError otPlatSettingsAbandonChange(otInstance *aInstance)
{
(void)aInstance;
return OT_ERROR_NONE;
}
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue,
uint16_t *aValueLength)
{
(void)aInstance;
(void)aKey;
(void)aIndex;
(void)aValue;
(void)aValueLength;
return OT_ERROR_NONE;
}
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
(void)aInstance;
(void)aKey;
(void)aValue;
(void)aValueLength;
return OT_ERROR_NONE;
}
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
(void)aInstance;
(void)aKey;
(void)aValue;
(void)aValueLength;
return OT_ERROR_NONE;
}
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
{
(void)aInstance;
(void)aKey;
(void)aIndex;
return OT_ERROR_NONE;
}
void otPlatSettingsWipe(otInstance *aInstance)
{
(void)aInstance;
}
} // extern "C"