<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "ble-blocktransfer/BlockTransferService.h"
#include "voytalk/Voytalk.h"

/*****************************************************************************/
/* Configuration                                                             */
/*****************************************************************************/

// set device name
const char DEVICE_NAME[] = "Testoy";

// set TX power
#ifndef CFG_BLE_TX_POWER_LEVEL
#define CFG_BLE_TX_POWER_LEVEL 0
#endif

// control debug output
#if 1
#define DEBUGOUT(...) { printf(__VA_ARGS__); }
#else
#define DEBUGOUT(...) /* nothing */
#endif // DEBUGOUT

#define VERBOSE_DEBUG_OUT 1

/*****************************************************************************/

/* Voytalk short UUID */
const UUID uuid(0xFE8E);

/* Voytalk states */
typedef enum {
    FLAG_CONNECTED      = 0x01,
    FLAG_PROVISIONED    = 0x02,
} flags_t;

static volatile uint8_t state;

/*****************************************************************************/
/* Global variables used by the test app                                     */
/*****************************************************************************/

// BLE_API ble device
BLE ble;

// Transfer large blocks of data on platforms without Fragmentation-And-Recombination
BlockTransferService bts;

// buffer for sending data
uint8_t readBuffer[1000];
SharedPointer<Block> readBlock(new BlockStatic(readBuffer, sizeof(readBuffer)));

// wifi parameters
std::string ssid_string;
std::string key_string;

// Compatibility function
void signalReady();

void onResponseFinished(const VTResponse& res)
{
    DEBUGOUT("main: output buffer usage: %lu of %lu\r\n", readBlock->getLength(), readBlock->getMaxLength());
    signalReady();
}

// Voytalk handling
VoytalkRouter router(DEVICE_NAME, onResponseFinished);

/*****************************************************************************/
/* Functions for handling debug output                                       */
/*****************************************************************************/

/*
    Functions called when BLE device connects and disconnects.
*/
void whenConnected(const Gap::ConnectionCallbackParams_t* params)
{
    (void) params;
    DEBUGOUT("main: Connected: %d %d %d\r\n", params->connectionParams->minConnectionInterval,
                                              params->connectionParams->maxConnectionInterval,
                                              params->connectionParams->slaveLatency);

    // change state in main application
    state |= FLAG_CONNECTED;

    // change state inside Voytalk hub
    router.setStateMask(state);
}

void whenDisconnected(const Gap::DisconnectionCallbackParams_t*)
{
    DEBUGOUT("main: Disconnected!\r\n");
    DEBUGOUT("main: Restarting the advertising process\r\n");

    ble.gap().startAdvertising();

    // change state in main application
    state &= ~FLAG_CONNECTED;

    // change state inside Voytalk hub
    router.setStateMask(state);
}

/*****************************************************************************/
/* BlockTransfer callbacks for sending and receiving data                    */
/*****************************************************************************/

/*
    Function called when signaling client that new data is ready to be read.
*/
void blockServerSendNotification()
{
    DEBUGOUT("main: notify read updated\r\n");
    bts.updateCharacteristicValue((uint8_t*)"", 0);
}

/*
    Function called when device receives a read request over BLE.
*/
SharedPointer<Block> blockServerReadHandler(uint32_t offset)
{
    DEBUGOUT("main: block read\r\n");
    (void) offset;

#if VERBOSE_DEBUG_OUT
    /* print generated output */
    if (readBlock->getLength() > 0)
    {
        for (size_t idx = 0; idx < readBlock->getLength(); idx++)
        {
            DEBUGOUT("%02X", readBlock->at(idx));
        }
        DEBUGOUT("\r\n\r\n");
    }
#endif

    return readBlock;
}

/*
    Function called when data has been written over BLE.
*/
void blockServerWriteHandler(SharedPointer<Block> block)
{
    DEBUGOUT("main: block write\r\n");

#if VERBOSE_DEBUG_OUT
    DEBUGOUT("main write:\r\n");
    for (size_t idx = 0; idx < block->getLength(); idx++)
    {
        DEBUGOUT("%02X", block->at(idx));
    }
    DEBUGOUT("\r\n\r\n");
#endif

    /*
        Process received data, assuming it is CBOR encoded.
        Any output generated will be written to the readBlock.
    */

    DEBUGOUT("main: input buffer usage: %lu of %lu\r\n", block->getLength(), block->getMaxLength());

    router.processCBOR((BlockStatic*) block.get(), (BlockStatic*) readBlock.get());
}

/*****************************************************************************/
/* Voytalk Wifi example                                                      */
/*****************************************************************************/

/*
    Callback function for constructing wifi intent.
*/
void wifiIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: wifi intent construction\r\n");
    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.connectivity.wifi");
    intent.knownParameters("/networks")
        .endpoint("/wifi");

    res.write(intent);
}

/*****************************************************************************/
/* Reset device example                                                      */
/*****************************************************************************/

void resetIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: reset intent construction\r\n");

    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.reset");
    intent.endpoint("/reset");
    res.write(intent);
}

/*****************************************************************************/
/* Voytalk complex example                                                   */
/*****************************************************************************/

/*
    Callback functions for the example intent.
*/
void exampleIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: complex example intent construction\r\n");

    /* create intent */
    VTIntent intent("com.arm.examples.complex");
    intent.endpoint("/examples/complex");

    res.write(intent);
}

/*****************************************************************************/
/* Voytalk custom example                                                    */
/*****************************************************************************/

void customIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: custom intent construction\r\n");
    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.examples.custom");
    intent.endpoint("/custom")
        .constraints()
            .title("Hello!")
            .description("This is the description")
            .addProperty("test",
                VTConstraint(VTConstraint::TypeString)
                    .title("Test")
                    .defaultValue("default goes here")
            )
            .addProperty("test2",
                VTConstraint(VTConstraint::TypeString)
                    .title("Other test")
                    .defaultValue("default goes here")
            );
    res.write(intent);
}

/*****************************************************************************/
/* Middleware for actually doing stuff                                       */
/*****************************************************************************/

void printInvocation(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    VTIntentInvocation invocation(req.getBody());
    invocation.getParameters().print();
    next();
}

void saveWifi(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: saving wifi details\r\n");

    VTIntentInvocation invocation(req.getBody());

    invocation.getParameters().find("ssid").getString(ssid_string);
    invocation.getParameters().find("key").getString(key_string);

    // change state in main application
    state |= FLAG_PROVISIONED;

    // change state inside Voytalk hub
    router.setStateMask(state);

    next();
}

void resetDevice(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: reset device\r\n");

    ssid_string = "";
    key_string = "";

    // change state in main application
    state &= ~FLAG_PROVISIONED;

    // change state inside Voytalk hub
    router.setStateMask(state);

    next();
}

void sendSuccess(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: sending success coda\r\n");
    VTIntentInvocation invocation(req.getBody());
    VTCoda coda(invocation.getID());
    coda.success(true);
    res.write(coda);
    next(200);
}

void networkList(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: listing network resources");

    VoytalkKnownParameters parameters(res, 2);

    parameters.parameter("com.arm.connectivity.wifi", 50)
        .map(2)
            .key("ssid").value("miWifi")
            .key("key").value("supersecurepassword");

    parameters.parameter("com.arm.connectivity.wifi", 20)
        .map(2)
            .key("ssid").value("yoWifi")
            .key("key").value("securepasswordinit");

    next(200);
}

/*****************************************************************************/
/* main                                                                      */
/*****************************************************************************/

void app_start(int, char *[])
{
    /*
        Register Voytalk intents in the hub.

        First parameter is the callback function for intent generation.
        Second parameter is a bitmap for grouping intents together.
    */

    // Wifi provisioning intent
    router.registerIntent(wifiIntentConstruction,
                          FLAG_CONNECTED | FLAG_PROVISIONED);

    // reset intent
    router.registerIntent(resetIntentConstruction,
                          FLAG_PROVISIONED);

    // custom intent
    //router.registerIntent(customIntentConstruction,
    //                     FLAG_CONNECTED | FLAG_PROVISIONED);

    // example intent
    router.registerIntent(exampleIntentConstruction,
                         FLAG_CONNECTED | FLAG_PROVISIONED);

    /*
        Set the current state mask.

        Mask is AND'ed with each intent's bitmap and only intents with non-zero
        results are displayed and can be invoked.
    */
    router.setStateMask(0);

    /*
        Define some resource callbacks
    */

    router.get("/networks",          networkList,                               NULL);
    router.post("/wifi",             printInvocation, saveWifi,    sendSuccess, NULL);
    router.post("/reset",            printInvocation, resetDevice, sendSuccess, NULL);
    router.post("/custom",           printInvocation,              sendSuccess, NULL);
    router.post("/examples/complex", printInvocation,              sendSuccess, NULL);

    /*************************************************************************/
    /*************************************************************************/
    /* bluetooth le */
    ble.init();

    // status callback functions
    ble.gap().onConnection(whenConnected);
    ble.gap().onDisconnection(whenDisconnected);

    /* construct advertising beacon */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED|GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, uuid.getBaseUUID(), uuid.getLen());
    ble.gap().accumulateAdvertisingPayloadTxPower(CFG_BLE_TX_POWER_LEVEL);

    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1s; in multiples of 0.625ms. */

    // set TX power
    ble.gap().setTxPower(CFG_BLE_TX_POWER_LEVEL);

    // Apple uses device name instead of beacon name
    ble.gap().setDeviceName((const uint8_t*) DEVICE_NAME);

    /*************************************************************************/
    /*************************************************************************/
    // setup block transfer service

    // add service using ble device, responding to uuid, and without encryption
    bts.init(uuid, SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK);

    // set callback functions for the BlockTransfer service
    bts.setWriteAuthorizationCallback(blockServerWriteHandler);
    bts.setReadAuthorizationCallback(blockServerReadHandler);

    // ble setup complete - start advertising
    ble.gap().startAdvertising();

    printf("Voytalk Test: %s %s\r\n", __DATE__, __TIME__);
}

/*****************************************************************************/
/* Compatibility                                                             */
/*****************************************************************************/

#if defined(YOTTA_MINAR_VERSION_STRING)
/*********************************************************/
/* Build for mbed OS                                     */
/*********************************************************/

void signalReady()
{
    minar::Scheduler::postCallback(blockServerSendNotification);
}

#else
/*********************************************************/
/* Build for mbed Classic                                */
/*********************************************************/

volatile bool sendNotification = false;

void signalReady()
{
    sendNotification = true;
}

int main(void)
{
    app_start(0, NULL);

    for(;;)
    {
        // send notification outside of interrupt context
        if (sendNotification)
        {
            sendNotification = false;
            blockServerSendNotification();
        }

        ble.waitForEvent();
    }
}
#endif

<commit_msg>use stream API for know parameters<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "ble-blocktransfer/BlockTransferService.h"
#include "voytalk/Voytalk.h"

/*****************************************************************************/
/* Configuration                                                             */
/*****************************************************************************/

// set device name
const char DEVICE_NAME[] = "Testoy";

// set TX power
#ifndef CFG_BLE_TX_POWER_LEVEL
#define CFG_BLE_TX_POWER_LEVEL 0
#endif

// control debug output
#if 1
#define DEBUGOUT(...) { printf(__VA_ARGS__); }
#else
#define DEBUGOUT(...) /* nothing */
#endif // DEBUGOUT

#define VERBOSE_DEBUG_OUT 1

/*****************************************************************************/

/* Voytalk short UUID */
const UUID uuid(0xFE8E);

/* Voytalk states */
typedef enum {
    FLAG_CONNECTED      = 0x01,
    FLAG_PROVISIONED    = 0x02,
} flags_t;

static volatile uint8_t state;

/*****************************************************************************/
/* Global variables used by the test app                                     */
/*****************************************************************************/

// BLE_API ble device
BLE ble;

// Transfer large blocks of data on platforms without Fragmentation-And-Recombination
BlockTransferService bts;

// buffer for sending data
uint8_t readBuffer[1000];
SharedPointer<Block> readBlock(new BlockStatic(readBuffer, sizeof(readBuffer)));

// wifi parameters
std::string ssid_string;
std::string key_string;

// Compatibility function
void signalReady();

void onResponseFinished(const VTResponse& res)
{
    DEBUGOUT("main: output buffer usage: %lu of %lu\r\n", readBlock->getLength(), readBlock->getMaxLength());
    signalReady();
}

// Voytalk handling
VoytalkRouter router(DEVICE_NAME, onResponseFinished);

/*****************************************************************************/
/* Functions for handling debug output                                       */
/*****************************************************************************/

/*
    Functions called when BLE device connects and disconnects.
*/
void whenConnected(const Gap::ConnectionCallbackParams_t* params)
{
    (void) params;
    DEBUGOUT("main: Connected: %d %d %d\r\n", params->connectionParams->minConnectionInterval,
                                              params->connectionParams->maxConnectionInterval,
                                              params->connectionParams->slaveLatency);

    // change state in main application
    state |= FLAG_CONNECTED;

    // change state inside Voytalk hub
    router.setStateMask(state);
}

void whenDisconnected(const Gap::DisconnectionCallbackParams_t*)
{
    DEBUGOUT("main: Disconnected!\r\n");
    DEBUGOUT("main: Restarting the advertising process\r\n");

    ble.gap().startAdvertising();

    // change state in main application
    state &= ~FLAG_CONNECTED;

    // change state inside Voytalk hub
    router.setStateMask(state);
}

/*****************************************************************************/
/* BlockTransfer callbacks for sending and receiving data                    */
/*****************************************************************************/

/*
    Function called when signaling client that new data is ready to be read.
*/
void blockServerSendNotification()
{
    DEBUGOUT("main: notify read updated\r\n");
    bts.updateCharacteristicValue((uint8_t*)"", 0);
}

/*
    Function called when device receives a read request over BLE.
*/
SharedPointer<Block> blockServerReadHandler(uint32_t offset)
{
    DEBUGOUT("main: block read\r\n");
    (void) offset;

#if VERBOSE_DEBUG_OUT
    /* print generated output */
    if (readBlock->getLength() > 0)
    {
        for (size_t idx = 0; idx < readBlock->getLength(); idx++)
        {
            DEBUGOUT("%02X", readBlock->at(idx));
        }
        DEBUGOUT("\r\n\r\n");
    }
#endif

    return readBlock;
}

/*
    Function called when data has been written over BLE.
*/
void blockServerWriteHandler(SharedPointer<Block> block)
{
    DEBUGOUT("main: block write\r\n");

#if VERBOSE_DEBUG_OUT
    DEBUGOUT("main write:\r\n");
    for (size_t idx = 0; idx < block->getLength(); idx++)
    {
        DEBUGOUT("%02X", block->at(idx));
    }
    DEBUGOUT("\r\n\r\n");
#endif

    /*
        Process received data, assuming it is CBOR encoded.
        Any output generated will be written to the readBlock.
    */

    DEBUGOUT("main: input buffer usage: %lu of %lu\r\n", block->getLength(), block->getMaxLength());

    router.processCBOR((BlockStatic*) block.get(), (BlockStatic*) readBlock.get());
}

/*****************************************************************************/
/* Voytalk Wifi example                                                      */
/*****************************************************************************/

/*
    Callback function for constructing wifi intent.
*/
void wifiIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: wifi intent construction\r\n");
    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.connectivity.wifi");
    intent.knownParameters("/networks")
        .endpoint("/wifi");

    res.write(intent);
}

/*****************************************************************************/
/* Reset device example                                                      */
/*****************************************************************************/

void resetIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: reset intent construction\r\n");

    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.reset");
    intent.endpoint("/reset");
    res.write(intent);
}

/*****************************************************************************/
/* Voytalk complex example                                                   */
/*****************************************************************************/

/*
    Callback functions for the example intent.
*/
void exampleIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: complex example intent construction\r\n");

    /* create intent */
    VTIntent intent("com.arm.examples.complex");
    intent.endpoint("/examples/complex");

    res.write(intent);
}

/*****************************************************************************/
/* Voytalk custom example                                                    */
/*****************************************************************************/

void customIntentConstruction(VTRequest& req, VTResponse& res)
{
    DEBUGOUT("main: custom intent construction\r\n");
    /* create intent using generated endpoint and constraint set */
    VTIntent intent("com.arm.examples.custom");
    intent.endpoint("/custom")
        .constraints()
            .title("Hello!")
            .description("This is the description")
            .addProperty("test",
                VTConstraint(VTConstraint::TypeString)
                    .title("Test")
                    .defaultValue("default goes here")
            )
            .addProperty("test2",
                VTConstraint(VTConstraint::TypeString)
                    .title("Other test")
                    .defaultValue("default goes here")
            );
    res.write(intent);
}

/*****************************************************************************/
/* Middleware for actually doing stuff                                       */
/*****************************************************************************/

void printInvocation(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    VTIntentInvocation invocation(req.getBody());
    invocation.getParameters().print();
    next();
}

void saveWifi(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: saving wifi details\r\n");

    VTIntentInvocation invocation(req.getBody());

    invocation.getParameters().find("ssid").getString(ssid_string);
    invocation.getParameters().find("key").getString(key_string);

    // change state in main application
    state |= FLAG_PROVISIONED;

    // change state inside Voytalk hub
    router.setStateMask(state);

    next();
}

void resetDevice(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: reset device\r\n");

    ssid_string = "";
    key_string = "";

    // change state in main application
    state &= ~FLAG_PROVISIONED;

    // change state inside Voytalk hub
    router.setStateMask(state);

    next();
}

void sendSuccess(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: sending success coda\r\n");
    VTIntentInvocation invocation(req.getBody());
    VTCoda coda(invocation.getID());
    coda.success(true);
    res.write(coda);
    next(200);
}

void networkList(VTRequest& req, VTResponse& res, VoytalkRouter::next_t next)
{
    DEBUGOUT("main: listing network resources");

    VoytalkKnownParameters parameters(res, 2);

    parameters.parameter("com.arm.connectivity.wifi", 50)
        .map()
            .key("ssid").value("miWifi")
        .end();

    parameters.parameter("com.arm.connectivity.wifi", 20)
        .map()
            .key("ssid").value("yoWifi")
        .end();

    next(200);
}

/*****************************************************************************/
/* main                                                                      */
/*****************************************************************************/

void app_start(int, char *[])
{
    /*
        Register Voytalk intents in the hub.

        First parameter is the callback function for intent generation.
        Second parameter is a bitmap for grouping intents together.
    */

    // Wifi provisioning intent
    router.registerIntent(wifiIntentConstruction,
                          FLAG_CONNECTED | FLAG_PROVISIONED);

    // reset intent
    router.registerIntent(resetIntentConstruction,
                          FLAG_PROVISIONED);

    // custom intent
    //router.registerIntent(customIntentConstruction,
    //                     FLAG_CONNECTED | FLAG_PROVISIONED);

    // example intent
    router.registerIntent(exampleIntentConstruction,
                         FLAG_CONNECTED | FLAG_PROVISIONED);

    /*
        Set the current state mask.

        Mask is AND'ed with each intent's bitmap and only intents with non-zero
        results are displayed and can be invoked.
    */
    router.setStateMask(0);

    /*
        Define some resource callbacks
    */

    router.get("/networks",          networkList,                               NULL);
    router.post("/wifi",             printInvocation, saveWifi,    sendSuccess, NULL);
    router.post("/reset",            printInvocation, resetDevice, sendSuccess, NULL);
    router.post("/custom",           printInvocation,              sendSuccess, NULL);
    router.post("/examples/complex", printInvocation,              sendSuccess, NULL);

    /*************************************************************************/
    /*************************************************************************/
    /* bluetooth le */
    ble.init();

    // status callback functions
    ble.gap().onConnection(whenConnected);
    ble.gap().onDisconnection(whenDisconnected);

    /* construct advertising beacon */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED|GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, uuid.getBaseUUID(), uuid.getLen());
    ble.gap().accumulateAdvertisingPayloadTxPower(CFG_BLE_TX_POWER_LEVEL);

    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1s; in multiples of 0.625ms. */

    // set TX power
    ble.gap().setTxPower(CFG_BLE_TX_POWER_LEVEL);

    // Apple uses device name instead of beacon name
    ble.gap().setDeviceName((const uint8_t*) DEVICE_NAME);

    /*************************************************************************/
    /*************************************************************************/
    // setup block transfer service

    // add service using ble device, responding to uuid, and without encryption
    bts.init(uuid, SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK);

    // set callback functions for the BlockTransfer service
    bts.setWriteAuthorizationCallback(blockServerWriteHandler);
    bts.setReadAuthorizationCallback(blockServerReadHandler);

    // ble setup complete - start advertising
    ble.gap().startAdvertising();

    printf("Voytalk Test: %s %s\r\n", __DATE__, __TIME__);
}

/*****************************************************************************/
/* Compatibility                                                             */
/*****************************************************************************/

#if defined(YOTTA_MINAR_VERSION_STRING)
/*********************************************************/
/* Build for mbed OS                                     */
/*********************************************************/

void signalReady()
{
    minar::Scheduler::postCallback(blockServerSendNotification);
}

#else
/*********************************************************/
/* Build for mbed Classic                                */
/*********************************************************/

volatile bool sendNotification = false;

void signalReady()
{
    sendNotification = true;
}

int main(void)
{
    app_start(0, NULL);

    for(;;)
    {
        // send notification outside of interrupt context
        if (sendNotification)
        {
            sendNotification = false;
            blockServerSendNotification();
        }

        ble.waitForEvent();
    }
}
#endif

<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <atomic>
#include <mutex>
#include <tbb/tbb.h>
#include <unordered_map>

using namespace tbb;
using namespace std;

inline uint64_t hashKey(uint64_t k) {
   // MurmurHash64A
   const uint64_t m = 0xc6a4a7935bd1e995;
   const int r = 47;
   uint64_t h = 0x8445d61a4e774912 ^ (8*m);
   k *= m;
   k ^= k >> r;
   k *= m;
   h ^= k;
   h *= m;
   h ^= h >> r;
   h *= m;
   h ^= h >> r;
   return h|(1ull<<63);
}

class ChainingLockingHT {
    // Chained tuple entry
    public: struct Entry {
        uint64_t key;
        uint64_t value;
        Entry* next;
    };

    struct Chain {
        std::mutex lock;
        Entry* head;
        uint64_t size;
        Chain() : head(nullptr), size(0) {}
    };
    private:
        unordered_map<uint64_t, Chain*> table;
    public:

    // Constructor
    ChainingLockingHT(uint64_t size) {
        this->table = unordered_map<uint64_t, Chain*>();
    }

    // Destructor
    ~ChainingLockingHT() {
    }

    // Returns the number of hits
    inline uint64_t lookup(uint64_t key) {
        return this->table[key]->size;
    }

    inline void insert(Entry* entry) {
        uint64_t key = hashKey(entry->key);
        Chain* chain = this->table[key];
		std::lock_guard<std::mutex> lock(chain->lock);

        Entry* curr = chain->head;
        while (curr->next != nullptr) {
            curr = curr->next;
        }
        curr->next = entry;
        chain->size++;
    }
};

class ChainingHT {

   // Chained tuple entry
   public: struct Entry {
      uint64_t key;
      uint64_t value;
      Entry* next;
   };

	private:
        unordered_map<uint64_t, ChainingHT::Entry*> hashTable;

	public:
		std::atomic<Entry*> nextOfCurrentEntry;

   // Constructor
   ChainingHT(uint64_t size){
		this->hashTable = unordered_map<uint64_t, ChainingHT::Entry*>();
   }

   // Destructor
   ~ChainingHT() {
   }

   // Returns the number of hits
   inline uint64_t lookup(uint64_t key) {
		uint64_t hashedKey = hashKey(key);
		if(this->hashTable.count(hashedKey) < 1){
			return 0;
		} else {
			Entry* e = hashTable.at(hashedKey);
			unsigned counter = 1;
			while(e->next != nullptr){
				counter++;
				e = e->next;
			}
			return counter;
		}
   }

   inline void insert(Entry* entry) {
      uint64_t hashValue = hashKey(entry->key);
		// if hashValue indicates an empty bucket, just insert
		if(this->hashTable.find(hashValue) == this->hashTable.end()){
			entry->next = nullptr;
			hashTable.emplace(hashValue, entry);
		} else {
			entry->next = nullptr;
			Entry* currentEntry = hashTable.at(hashValue);
			while(currentEntry->next != nullptr){
				currentEntry = currentEntry->next;
			}
			Entry* tmp = 0;
			nextOfCurrentEntry.store(currentEntry->next);
			while(!nextOfCurrentEntry.compare_exchange_weak(tmp, entry, memory_order_release, memory_order_relaxed));
			currentEntry->next = nextOfCurrentEntry.load();
			hashTable.emplace(hashValue, entry);
		}
   }
};

class LinearProbingHT {
   public:
   // Entry
   struct Entry {
      uint64_t key;
      uint64_t value;
      std::atomic<bool> marker;
   };

   // Constructor
   LinearProbingHT(uint64_t size) {
   }

   // Destructor
   ~LinearProbingHT() {
   }

   // Returns the number of hits
   inline uint64_t lookup(uint64_t key) {
   }

   inline void insert(uint64_t key, uint64_t value) {
   }
};

int main(int argc,char** argv) {
   uint64_t sizeR = atoi(argv[1]);
   uint64_t sizeS = atoi(argv[2]);
   unsigned threadCount = atoi(argv[3]);

   task_scheduler_init init(threadCount);

   // Init build-side relation R with random data
   uint64_t* R=static_cast<uint64_t*>(malloc(sizeR*sizeof(uint64_t)));
   parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
         unsigned int seed=range.begin();
         for (size_t i=range.begin(); i!=range.end(); ++i)
            R[i]=rand_r(&seed)%sizeR;
      });

   // Init probe-side relation S with random data
   uint64_t* S=static_cast<uint64_t*>(malloc(sizeS*sizeof(uint64_t)));
   parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
         unsigned int seed=range.begin();
         for (size_t i=range.begin(); i!=range.end(); ++i)
            S[i]=rand_r(&seed)%sizeR;
      });

   // STL
   {
      // Build hash table (single threaded)
      tick_count buildTS=tick_count::now();
      unordered_multimap<uint64_t,uint64_t> ht(sizeR);
      for (uint64_t i=0; i<sizeR; i++)
         ht.emplace(R[i],0);
      tick_count probeTS=tick_count::now();
      cout << "STL      	    build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

      // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
            for (size_t i=range.begin(); i!=range.end(); ++i) {
               auto range=ht.equal_range(S[i]);
               for (unordered_multimap<uint64_t,uint64_t>::iterator it=range.first; it!=range.second; ++it)
                  localHitCounter++;
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
   }

   // Test of ChainingLockingHT
   {
	  // Build hash table
      tick_count buildTS=tick_count::now();
      ChainingLockingHT* cl(new ChainingLockingHT(sizeR));
	  parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
			for (size_t i=range.begin(); i!=range.end(); ++i) {
                ChainingLockingHT::Entry* e(new ChainingLockingHT::Entry());
		 		e->key = R[i];
		 		e->value = 0;	//see your STL Test
  //-----      		cl->insert(e);
            }
	  	 });
	  tick_count probeTS=tick_count::now();
      cout << "ChainingLockingHT   build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

	  // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
			for (size_t i=range.begin(); i!=range.end(); ++i) {
  //-----            localHitCounter += cl->lookup(S[i]);
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
	}

   // Test of ChainingHT
   {
	  // Build hash table
      tick_count buildTS=tick_count::now();
      ChainingHT* c(new ChainingHT(sizeR));
	  parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
			for (size_t i=range.begin(); i!=range.end(); ++i) {
                ChainingHT::Entry* e(new ChainingHT::Entry());
		 		e->key = R[i];
		 		e->value = 0;	//see your STL Test
         		c->insert(e);
            }
	  	 });
	  tick_count probeTS=tick_count::now();
      cout << "ChainingHT          build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

	  // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
			for (size_t i=range.begin(); i!=range.end(); ++i) {
               localHitCounter += c->lookup(S[i]);
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
	}

   // Test of LinearProbing
   {
	  // Build hash table
      tick_count buildTS=tick_count::now();
      LinearProbingHT* lp(new LinearProbingHT(sizeR));
	  parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
			for (size_t i=range.begin(); i!=range.end(); ++i) {
         		lp->insert(R[i], 0);	  //see your STL Test
            }
	  	 });
	  tick_count probeTS=tick_count::now();
      cout << "LinearProbingHT     build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

	  // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
			for (size_t i=range.begin(); i!=range.end(); ++i) {
               localHitCounter += lp->lookup(S[i]);
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
	}

   return 0;
}
<commit_msg>bugfixes for chainingLockingHt, the test now runs without segmentation fault<commit_after>#include <iostream>
#include <cstdlib>
#include <atomic>
#include <mutex>
#include <tbb/tbb.h>
#include <unordered_map>

using namespace tbb;
using namespace std;

inline uint64_t hashKey(uint64_t k) {
   // MurmurHash64A
   const uint64_t m = 0xc6a4a7935bd1e995;
   const int r = 47;
   uint64_t h = 0x8445d61a4e774912 ^ (8*m);
   k *= m;
   k ^= k >> r;
   k *= m;
   h ^= k;
   h *= m;
   h ^= h >> r;
   h *= m;
   h ^= h >> r;
   return h|(1ull<<63);
}

class ChainingLockingHT {
    // Chained tuple entry
    public: struct Entry {
        uint64_t key;
        uint64_t value;
        Entry* next;
    };

    struct Chain {
        std::mutex lock;
        Entry* head;
        uint64_t size;
        Chain() : head(nullptr), size(0) {}
    };
    private:
        unordered_map<uint64_t, Chain*> table;
    public:

    // Constructor
    ChainingLockingHT(uint64_t size) {
        this->table = unordered_map<uint64_t, Chain*>();
    }

    // Destructor
    ~ChainingLockingHT() {
    }

    // Returns the number of hits
    inline uint64_t lookup(uint64_t key) {
        return this->table[hashKey(key)]->size;
    }

    inline void insert(Entry* entry) {
        uint64_t key = hashKey(entry->key);
		Chain* chain;
		if(this->table.find(key) == this->table.end()){
			entry->next = nullptr;
			chain = new Chain();
			chain->head = entry;
			chain->size++;
			this->table.emplace(key, chain);
		} else {
			Chain* chain = this->table[key];
			std::lock_guard<std::mutex> lock(chain->lock);

        	Entry* curr = chain->head;
        	while (curr->next != nullptr) {
            	curr = curr->next;
        	}
       		curr->next = entry;
        	chain->size++;
		}
    }
};

class ChainingHT {

   // Chained tuple entry
   public: struct Entry {
      uint64_t key;
      uint64_t value;
      Entry* next;
   };

	private:
        unordered_map<uint64_t, ChainingHT::Entry*> hashTable;

	public:
		std::atomic<Entry*> nextOfCurrentEntry;

   // Constructor
   ChainingHT(uint64_t size){
		this->hashTable = unordered_map<uint64_t, ChainingHT::Entry*>(size);
   }

   // Destructor
   ~ChainingHT() {
   }

   // Returns the number of hits
   inline uint64_t lookup(uint64_t key) {
		uint64_t hashedKey = hashKey(key);
		if(this->hashTable.count(hashedKey) < 1){
			return 0;
		} else {
			Entry* e = hashTable.at(hashedKey);
			unsigned counter = 1;
			while(e->next != nullptr){
				counter++;
				e = e->next;
			}
			return counter;
		}
   }

   inline void insert(Entry* entry) {
      uint64_t hashValue = hashKey(entry->key);
		// if hashValue indicates an empty bucket, just insert
		if(this->hashTable.find(hashValue) == this->hashTable.end()){
			entry->next = nullptr;
			hashTable.emplace(hashValue, entry);
		} else {
			entry->next = nullptr;
			Entry* currentEntry = hashTable.at(hashValue);
			while(currentEntry->next != nullptr){
				currentEntry = currentEntry->next;
			}
			Entry* tmp = 0;
			nextOfCurrentEntry.store(currentEntry->next);
			while(!nextOfCurrentEntry.compare_exchange_weak(tmp, entry, memory_order_release, memory_order_relaxed));
			currentEntry->next = nextOfCurrentEntry.load();
			hashTable.emplace(hashValue, entry);
		}
   }
};

class LinearProbingHT {
   public:
   // Entry
   struct Entry {
      uint64_t key;
      uint64_t value;
      std::atomic<bool> marker;
   };

   // Constructor
   LinearProbingHT(uint64_t size) {
   }

   // Destructor
   ~LinearProbingHT() {
   }

   // Returns the number of hits
   inline uint64_t lookup(uint64_t key) {
   }

   inline void insert(uint64_t key, uint64_t value) {
   }
};

int main(int argc,char** argv) {
   uint64_t sizeR = atoi(argv[1]);
   uint64_t sizeS = atoi(argv[2]);
   unsigned threadCount = atoi(argv[3]);

   task_scheduler_init init(threadCount);

   // Init build-side relation R with random data
   uint64_t* R=static_cast<uint64_t*>(malloc(sizeR*sizeof(uint64_t)));
   parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
         unsigned int seed=range.begin();
         for (size_t i=range.begin(); i!=range.end(); ++i)
            R[i]=rand_r(&seed)%sizeR;
      });

   // Init probe-side relation S with random data
   uint64_t* S=static_cast<uint64_t*>(malloc(sizeS*sizeof(uint64_t)));
   parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
         unsigned int seed=range.begin();
         for (size_t i=range.begin(); i!=range.end(); ++i)
            S[i]=rand_r(&seed)%sizeR;
      });

   // STL
   {
      // Build hash table (single threaded)
      tick_count buildTS=tick_count::now();
      unordered_multimap<uint64_t,uint64_t> ht(sizeR);
      for (uint64_t i=0; i<sizeR; i++)
         ht.emplace(R[i],0);
      tick_count probeTS=tick_count::now();
      cout << "STL      	    build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

      // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
            for (size_t i=range.begin(); i!=range.end(); ++i) {
               auto range=ht.equal_range(S[i]);
               for (unordered_multimap<uint64_t,uint64_t>::iterator it=range.first; it!=range.second; ++it)
                  localHitCounter++;
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
   }

   // Test of ChainingLockingHT
   {
	  // Build hash table
      tick_count buildTS=tick_count::now();
      ChainingLockingHT* cl(new ChainingLockingHT(sizeR));
	  parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
			for (size_t i=range.begin(); i!=range.end(); ++i) {
                ChainingLockingHT::Entry* e(new ChainingLockingHT::Entry());
		 		e->key = R[i];
		 		e->value = 0;	//see your STL Test
        		cl->insert(e);
            }
	  	 });
	  tick_count probeTS=tick_count::now();
      cout << "ChainingLockingHT   build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

	  // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
			for (size_t i=range.begin(); i!=range.end(); ++i) {
  	           localHitCounter += cl->lookup(S[i]);
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
	}

   // Test of ChainingHT
   {
	  // Build hash table
      tick_count buildTS=tick_count::now();
      ChainingHT* c(new ChainingHT(sizeR));
	  parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
			for (size_t i=range.begin(); i!=range.end(); ++i) {
                ChainingHT::Entry* e(new ChainingHT::Entry());
		 		e->key = R[i];
		 		e->value = 0;	//see your STL Test
         		c->insert(e);
            }
	  	 });
	  tick_count probeTS=tick_count::now();
      cout << "ChainingHT          build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

	  // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
			for (size_t i=range.begin(); i!=range.end(); ++i) {
               localHitCounter += c->lookup(S[i]);
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
	}

   // Test of LinearProbing
   {
	  // Build hash table
      tick_count buildTS=tick_count::now();
      LinearProbingHT* lp(new LinearProbingHT(sizeR));
	  parallel_for(blocked_range<size_t>(0, sizeR), [&](const blocked_range<size_t>& range) {
			for (size_t i=range.begin(); i!=range.end(); ++i) {
         		lp->insert(R[i], 0);	  //see your STL Test
            }
	  	 });
	  tick_count probeTS=tick_count::now();
      cout << "LinearProbingHT     build:" << (sizeR/1e6)/(probeTS-buildTS).seconds() << "MT/s ";

	  // Probe hash table and count number of hits
      std::atomic<uint64_t> hitCounter;
      hitCounter=0;
      parallel_for(blocked_range<size_t>(0, sizeS), [&](const blocked_range<size_t>& range) {
            uint64_t localHitCounter=0;
			for (size_t i=range.begin(); i!=range.end(); ++i) {
               localHitCounter += lp->lookup(S[i]);
            }
            hitCounter+=localHitCounter;
         });
      tick_count stopTS=tick_count::now();
      cout << "probe: " << (sizeS/1e6)/(stopTS-probeTS).seconds() << "MT/s "
           << "total: " << ((sizeR+sizeS)/1e6)/(stopTS-buildTS).seconds() << "MT/s "
           << "count: " << hitCounter << endl;
	}

   return 0;
}
<|endoftext|>


<commit_before>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <cstdlib>
#include <cassert>

#include "api-loader.h"
#include "pointers.h"

#include <string>
#include <vector>
#include <stdexcept>

#ifdef USE_DETOURS
#include "detours/detours.h"
#endif

#ifdef USE_MHOOK
#include "mhook/mhook-lib/mhook.h"
#endif

#include "gl-wrappers.h"

#include <DGLCommon/os.h>

#ifndef _WIN32
#include "dl-intercept.h"
#endif

#ifdef _WIN32
#define LIBGL_NAME     "opengl32.dll"
#define LIBGLES1_NAME  "libGLESv1_CM.dll"
#define LIBGLES2_NAME  "libGLESv2.dll"
#define LIBEGL_NAME    "libEGL.dll"
#define STRIP_VERSION(X) X
#elif defined(__ANDROID__)
//on Android libraries are not opened by SONAME
#define LIBGL_NAME    "libGL.so"
#define LIBGLES1_NAME "libGLESv1_CM.so"
#define LIBGLES2_NAME "libGLESv2.so"
#define LIBEGL_NAME   "libEGL.so"
#define STRIP_VERSION(X) X
#else
#define LIBGL_NAME    "libGL.so.1"
#define LIBGLES1_NAME "libGLESv1_CM.so.1"
#define LIBGLES2_NAME "libGLESv2.so.1"
#define LIBEGL_NAME   "libEGL.so.1"
#define STRIP_VERSION(X) std::string(X).substr(0, std::string(X).length() - strlen(".1"))
#endif

//here direct pointers are kept (pointers to entrypoints exposed by underlying OpenGL32 implementation
//use DIRECT_CALL(name) to call one of these pointers
LoadedPointer g_DirectPointers[Entrypoints_NUM] = {
#define FUNC_LIST_ELEM_SUPPORTED(name, type, library) { NULL, library},
#define FUNC_LIST_ELEM_NOT_SUPPORTED(name, type, library) FUNC_LIST_ELEM_SUPPORTED(name, type, library)
    #include "codegen/functionList.inl"
#undef FUNC_LIST_ELEM_SUPPORTED
#undef FUNC_LIST_ELEM_NOT_SUPPORTED
};

APILoader::APILoader():m_LoadedApiLibraries(LIBRARY_NONE),m_GlueLibrary(LIBRARY_NONE) {}

FUNC_PTR APILoader::loadGLPointer(LoadedLib library, Entrypoint entryp) {
#ifdef _WIN32
    return GetProcAddress((HINSTANCE)library, GetEntryPointName(entryp));
#else
    //(int) -> see http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
    return reinterpret_cast<FUNC_PTR>((ptrdiff_t)dlsym(library, GetEntryPointName(entryp)));
#endif
}

bool APILoader::loadExtPointer(Entrypoint entryp) {
    if (!g_DirectPointers[entryp].ptr) {

        if (!m_GlueLibrary) {
            throw std::runtime_error("Trying to call *GetProcAdress, but no glue library loaded");
        }

        FUNC_PTR ptr = NULL;

        switch (m_GlueLibrary) {
#ifdef HAVE_LIBRARY_WGL
        case LIBRARY_WGL:
            ptr  = DIRECT_CALL(wglGetProcAddress)(GetEntryPointName(entryp));
            break;
#endif
#ifdef HAVE_LIBRARY_GLX
        case LIBRARY_GLX:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(glXGetProcAddress)(
                        reinterpret_cast<const GLubyte*>(GetEntryPointName(entryp))));
            break;
#endif
        case LIBRARY_EGL:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(eglGetProcAddress)(GetEntryPointName(entryp)));
            break;
        default:
            assert(!"unknown glue library");
        }
        g_DirectPointers[entryp].ptr = ptr;
    }
    return g_DirectPointers[entryp].ptr != NULL;
}

std::string APILoader::getLibraryName(ApiLibrary apiLibrary) {
    switch (apiLibrary) {
        case LIBRARY_EGL:
            return LIBEGL_NAME;
        case LIBRARY_GL:
        case LIBRARY_WGL:
        case LIBRARY_GLX:
            return LIBGL_NAME;
        case LIBRARY_ES1:
            return LIBGLES1_NAME;
        case LIBRARY_ES2:
        case LIBRARY_ES3:
            return LIBGLES2_NAME;
        default:
            assert(!"unknown library");
            throw std::runtime_error("Unknown GL library name");
    }
}

bool APILoader::isLibGL(const char* name) {
    std::string nameStr(name);
    bool ret = nameStr.find(STRIP_VERSION(LIBGL_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES1_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES2_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBEGL_NAME)) != std::string::npos;

    Os::info("isLibGL(%s) == %d", name, (int) ret);

    return ret;

}

void APILoader::setPointer(Entrypoint entryp, FUNC_PTR direct) {
    if (entryp < NO_ENTRYPOINT) {
         g_DirectPointers[entryp].ptr = direct;
    }
}

void APILoader::loadLibrary(ApiLibrary apiLibrary) {

    Os::info("loadLibrary()");
    std::string libraryName = getLibraryName(apiLibrary);

    Os::info("loadLibrary(%s)", libraryName.c_str());

    if (m_LoadedLibraries.find(libraryName) == m_LoadedLibraries.end()) {

        Os::info("loadLibrary(): not loaded, yet");

        std::vector<std::string> libSearchPath;

        LoadedLib openGLLibraryHandle = NULL;

        libSearchPath.push_back("");
#ifdef _WIN32
        char buffer[1000];
#ifndef _WIN64
        if (GetSystemWow64Directory(buffer, sizeof(buffer)) > 0) {
            //we are running 32bit app on 64 bit windows
            libSearchPath.push_back(buffer + std::string("\\"));
        }
#endif
        if (!openGLLibraryHandle) {
            if (GetSystemDirectory(buffer, sizeof(buffer)) > 0) {
                //we are running on native system (32 on 32 or 64 on 64)
                libSearchPath.push_back(buffer + std::string("\\"));
            }
        }
#ifndef _WIN64
        libSearchPath.push_back("C:\\Windows\\SysWOW64\\");
#endif
        libSearchPath.push_back("C:\\Windows\\System32\\");
        libSearchPath.push_back(".");
#endif

        for (size_t i = 0; i < libSearchPath.size() && !openGLLibraryHandle; i++) {
#ifdef _WIN32
            openGLLibraryHandle = (LoadedLib)LoadLibrary((libSearchPath[i] + libraryName).c_str());
#else
            openGLLibraryHandle = dlopen((libSearchPath[i] + libraryName).c_str(), RTLD_NOW);
#endif
        }

        if (!openGLLibraryHandle) {
            std::string msg = std::string("Cannot load ") + libraryName + "  system library";
            Os::fatal(msg.c_str());
        } else {
            m_LoadedLibraries[libraryName] = openGLLibraryHandle;
        }
    }

    LoadedLib library = m_LoadedLibraries[libraryName];

    //we use MS Detours only on win32, on x64 mHook is used
#ifdef USE_DETOURS
    DetourRestoreAfterWith();
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
#endif
    //g_DirectPointers is now filled with opengl32.dll pointers
    // we will now detour (hook) them all, so g_DirectPointers will still lead to original opengl32.dll, but
    //application will always call us.
    for (int i = 0; i < Entrypoints_NUM; i++) {
        if (!(g_DirectPointers[i].libraryMask & apiLibrary)) {
            //Do not load - entrypoint does not belong to currently loaded API
            continue;
        }

        if (m_LoadedApiLibraries & g_DirectPointers[i].libraryMask) {
            //Do not load - entrypoint belongs to already loaded API
            continue;
        }

        //this sets g_DirectPointers[i].ptr
        setPointer(i, loadGLPointer(library, i));

        if (g_DirectPointers[i].ptr) {
            //this entrypoint was loaded from OpenGL32.dll, detour it!
#if defined(USE_DETOURS) || defined(USE_MHOOK)
            FUNC_PTR * hookPtr = getWrapperPointer(i);
#endif
#ifdef USE_DETOURS
            DetourAttach(&(PVOID&)g_DirectPointers[i].ptr, hookPtr);
#endif
#ifdef USE_MHOOK
            if (!Mhook_SetHook(&(PVOID&)g_DirectPointers[i].ptr, hookPtr)) {
                Os::fatal("Cannot hook %s() function.", GetEntryPointName(i));
            }
#endif
        }
    }
#ifdef USE_DETOURS
    DetourTransactionCommit();
#endif
    if (apiLibrary == LIBRARY_EGL || apiLibrary == LIBRARY_WGL || apiLibrary == LIBRARY_GLX)
        m_GlueLibrary = apiLibrary;

    m_LoadedApiLibraries |= apiLibrary;
}

FUNC_PTR APILoader::ensurePointer(Entrypoint entryp) {
    if (g_DirectPointers[entryp].ptr || loadExtPointer(entryp)) {
        return g_DirectPointers[entryp].ptr;
    } else {
        std::string error = "Operation aborted, because the ";
        error += GetEntryPointName(entryp);
        error += " function is not available on current context. Try updating GPU drivers.";
        throw std::runtime_error(error);
    }
}

APILoader g_ApiLoader;
<commit_msg>Remove some debug printfs.<commit_after>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <cstdlib>
#include <cassert>

#include "api-loader.h"
#include "pointers.h"

#include <string>
#include <vector>
#include <stdexcept>

#ifdef USE_DETOURS
#include "detours/detours.h"
#endif

#ifdef USE_MHOOK
#include "mhook/mhook-lib/mhook.h"
#endif

#include "gl-wrappers.h"

#include <DGLCommon/os.h>

#ifndef _WIN32
#include "dl-intercept.h"
#endif

#ifdef _WIN32
#define LIBGL_NAME     "opengl32.dll"
#define LIBGLES1_NAME  "libGLESv1_CM.dll"
#define LIBGLES2_NAME  "libGLESv2.dll"
#define LIBEGL_NAME    "libEGL.dll"
#define STRIP_VERSION(X) X
#elif defined(__ANDROID__)
//on Android libraries are not opened by SONAME
#define LIBGL_NAME    "libGL.so"
#define LIBGLES1_NAME "libGLESv1_CM.so"
#define LIBGLES2_NAME "libGLESv2.so"
#define LIBEGL_NAME   "libEGL.so"
#define STRIP_VERSION(X) X
#else
#define LIBGL_NAME    "libGL.so.1"
#define LIBGLES1_NAME "libGLESv1_CM.so.1"
#define LIBGLES2_NAME "libGLESv2.so.1"
#define LIBEGL_NAME   "libEGL.so.1"
#define STRIP_VERSION(X) std::string(X).substr(0, std::string(X).length() - strlen(".1"))
#endif

//here direct pointers are kept (pointers to entrypoints exposed by underlying OpenGL32 implementation
//use DIRECT_CALL(name) to call one of these pointers
LoadedPointer g_DirectPointers[Entrypoints_NUM] = {
#define FUNC_LIST_ELEM_SUPPORTED(name, type, library) { NULL, library},
#define FUNC_LIST_ELEM_NOT_SUPPORTED(name, type, library) FUNC_LIST_ELEM_SUPPORTED(name, type, library)
    #include "codegen/functionList.inl"
#undef FUNC_LIST_ELEM_SUPPORTED
#undef FUNC_LIST_ELEM_NOT_SUPPORTED
};

APILoader::APILoader():m_LoadedApiLibraries(LIBRARY_NONE),m_GlueLibrary(LIBRARY_NONE) {}

FUNC_PTR APILoader::loadGLPointer(LoadedLib library, Entrypoint entryp) {
#ifdef _WIN32
    return GetProcAddress((HINSTANCE)library, GetEntryPointName(entryp));
#else
    //(int) -> see http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
    return reinterpret_cast<FUNC_PTR>((ptrdiff_t)dlsym(library, GetEntryPointName(entryp)));
#endif
}

bool APILoader::loadExtPointer(Entrypoint entryp) {
    if (!g_DirectPointers[entryp].ptr) {

        if (!m_GlueLibrary) {
            throw std::runtime_error("Trying to call *GetProcAdress, but no glue library loaded");
        }

        FUNC_PTR ptr = NULL;

        switch (m_GlueLibrary) {
#ifdef HAVE_LIBRARY_WGL
        case LIBRARY_WGL:
            ptr  = DIRECT_CALL(wglGetProcAddress)(GetEntryPointName(entryp));
            break;
#endif
#ifdef HAVE_LIBRARY_GLX
        case LIBRARY_GLX:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(glXGetProcAddress)(
                        reinterpret_cast<const GLubyte*>(GetEntryPointName(entryp))));
            break;
#endif
        case LIBRARY_EGL:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(eglGetProcAddress)(GetEntryPointName(entryp)));
            break;
        default:
            assert(!"unknown glue library");
        }
        g_DirectPointers[entryp].ptr = ptr;
    }
    return g_DirectPointers[entryp].ptr != NULL;
}

std::string APILoader::getLibraryName(ApiLibrary apiLibrary) {
    switch (apiLibrary) {
        case LIBRARY_EGL:
            return LIBEGL_NAME;
        case LIBRARY_GL:
        case LIBRARY_WGL:
        case LIBRARY_GLX:
            return LIBGL_NAME;
        case LIBRARY_ES1:
            return LIBGLES1_NAME;
        case LIBRARY_ES2:
        case LIBRARY_ES3:
            return LIBGLES2_NAME;
        default:
            assert(!"unknown library");
            throw std::runtime_error("Unknown GL library name");
    }
}

bool APILoader::isLibGL(const char* name) {
    std::string nameStr(name);
    bool ret = nameStr.find(STRIP_VERSION(LIBGL_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES1_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES2_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBEGL_NAME)) != std::string::npos;

    return ret;

}

void APILoader::setPointer(Entrypoint entryp, FUNC_PTR direct) {
    if (entryp < NO_ENTRYPOINT) {
         g_DirectPointers[entryp].ptr = direct;
    }
}

void APILoader::loadLibrary(ApiLibrary apiLibrary) {

    std::string libraryName = getLibraryName(apiLibrary);

    if (m_LoadedLibraries.find(libraryName) == m_LoadedLibraries.end()) {

        std::vector<std::string> libSearchPath;

        LoadedLib openGLLibraryHandle = NULL;

        libSearchPath.push_back("");
#ifdef _WIN32
        char buffer[1000];
#ifndef _WIN64
        if (GetSystemWow64Directory(buffer, sizeof(buffer)) > 0) {
            //we are running 32bit app on 64 bit windows
            libSearchPath.push_back(buffer + std::string("\\"));
        }
#endif
        if (!openGLLibraryHandle) {
            if (GetSystemDirectory(buffer, sizeof(buffer)) > 0) {
                //we are running on native system (32 on 32 or 64 on 64)
                libSearchPath.push_back(buffer + std::string("\\"));
            }
        }
#ifndef _WIN64
        libSearchPath.push_back("C:\\Windows\\SysWOW64\\");
#endif
        libSearchPath.push_back("C:\\Windows\\System32\\");
        libSearchPath.push_back(".");
#endif

        for (size_t i = 0; i < libSearchPath.size() && !openGLLibraryHandle; i++) {
#ifdef _WIN32
            openGLLibraryHandle = (LoadedLib)LoadLibrary((libSearchPath[i] + libraryName).c_str());
#else
            openGLLibraryHandle = dlopen((libSearchPath[i] + libraryName).c_str(), RTLD_NOW);
#endif
        }

        if (!openGLLibraryHandle) {
            std::string msg = std::string("Cannot load ") + libraryName + "  system library";
            Os::fatal(msg.c_str());
        } else {
            m_LoadedLibraries[libraryName] = openGLLibraryHandle;
        }
    }

    LoadedLib library = m_LoadedLibraries[libraryName];

    //we use MS Detours only on win32, on x64 mHook is used
#ifdef USE_DETOURS
    DetourRestoreAfterWith();
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
#endif
    //g_DirectPointers is now filled with opengl32.dll pointers
    // we will now detour (hook) them all, so g_DirectPointers will still lead to original opengl32.dll, but
    //application will always call us.
    for (int i = 0; i < Entrypoints_NUM; i++) {
        if (!(g_DirectPointers[i].libraryMask & apiLibrary)) {
            //Do not load - entrypoint does not belong to currently loaded API
            continue;
        }

        if (m_LoadedApiLibraries & g_DirectPointers[i].libraryMask) {
            //Do not load - entrypoint belongs to already loaded API
            continue;
        }

        //this sets g_DirectPointers[i].ptr
        setPointer(i, loadGLPointer(library, i));

        if (g_DirectPointers[i].ptr) {
            //this entrypoint was loaded from OpenGL32.dll, detour it!
#if defined(USE_DETOURS) || defined(USE_MHOOK)
            FUNC_PTR * hookPtr = getWrapperPointer(i);
#endif
#ifdef USE_DETOURS
            DetourAttach(&(PVOID&)g_DirectPointers[i].ptr, hookPtr);
#endif
#ifdef USE_MHOOK
            if (!Mhook_SetHook(&(PVOID&)g_DirectPointers[i].ptr, hookPtr)) {
                Os::fatal("Cannot hook %s() function.", GetEntryPointName(i));
            }
#endif
        }
    }
#ifdef USE_DETOURS
    DetourTransactionCommit();
#endif
    if (apiLibrary == LIBRARY_EGL || apiLibrary == LIBRARY_WGL || apiLibrary == LIBRARY_GLX)
        m_GlueLibrary = apiLibrary;

    m_LoadedApiLibraries |= apiLibrary;
}

FUNC_PTR APILoader::ensurePointer(Entrypoint entryp) {
    if (g_DirectPointers[entryp].ptr || loadExtPointer(entryp)) {
        return g_DirectPointers[entryp].ptr;
    } else {
        std::string error = "Operation aborted, because the ";
        error += GetEntryPointName(entryp);
        error += " function is not available on current context. Try updating GPU drivers.";
        throw std::runtime_error(error);
    }
}

APILoader g_ApiLoader;
<|endoftext|>


<commit_before>#include "AvlTree.h"
#include <algorithm>
#include <cassert>
#include <utility>

AvlNode AVLNIL = {-1, -1, &AVLNIL, &AVLNIL, &AVLNIL};

#define is_nil(e) ((e) == &AVLNIL)
#define not_nil(e) ((e) != &AVLNIL)
#define set_nil(e) ((e) = &AVLNIL)
#define get_height(left, right) (std::max((left)->height, (right)->height) + 1)

AvlNode::AvlNode() {
  value = -1;
  height = -1;
  set_nil(left);
  set_nil(right);
  set_nil(father);
}

AvlNode::AvlNode(int v, int h, AvlNode *l, AvlNode *r, AvlNode *f) {
  value = v;
  height = h;
  left = l;
  right = r;
  father = f;
}

static void Free(AvlNode *e) {
  if (is_nil(e))
    return;
  Free(e->left);
  Free(e->right);
  delete e;
}

// left left case
// right-rotate
static void LL(AvlNode **e) {
  AvlNode *p;

  p = (*e)->left;
  (*e)->left = p->right;
  p->right = (*e);

  (*e)->height = get_height((*e)->left, (*e)->right);
  p->height = get_height(p->left, *e);
  (*e) = p;
}

// right right case
// left-rotate
static void RR(AvlNode **e) {
  AvlNode *p;

  p = (*e)->right;
  (*e)->right = p->left;
  p->left = (*e);

  (*e)->height = get_height((*e)->left, (*e)->right);
  p->height = get_height(p->right, *e);
  (*e) = p;
}

// left right case
// left-rotate, right-rotate -> RR, LL
static void LR(AvlNode **e) {
  RR(&((*e)->left));
  LL(e);
}

// right left case
// right-rotate, left-rotate -> LL, RR
static void RL(AvlNode **e) {
  LL(&((*e)->right));
  RR(e);
}

static AvlNode *Find(AvlNode *e, int value) {
  if (is_nil(e)) {
    return &AVLNIL;
  }
  //二分查找
  if (e->value == value) {
    return e;
  } else if (e->value > value) {
    return Find(e->left, value);
  } else {
    return Find(e->right, value);
  }
}

static void Fix(AvlNode *e) {
  e->height = get_height(e->left, e->right);
  int factor = e->left->height - e->right->height;
  if (factor > 1 && e->left->value > e->value) {
    LL(&e);
  }
  if (factor < -1 && e->right->value < e->value) {
    RR(&e);
  }
  if (factor > 1 && e->left->value < e->value) {
    LR(&e);
  }
  if (factor < -1 && e->right->value > e->value) {
    RL(&e);
  }
}

static void Insert(AvlNode **e, AvlNode *father, int value) {
  assert(e);
  assert(father);

  if (is_nil(*e)) {
    // *e is nil
    *e = new AvlNode();
    set_nil((*e)->left);
    set_nil((*e)->right);
    (*e)->father = father;
    (*e)->value = value;
    (*e)->height = get_height((*e)->left, (*e)->right);
    return;
  }

  //利用二分查找找到适合value插入的位置e

  if ((*e)->value > value) {
    Insert(&(*e)->left, *e, value);
  } else if ((*e)->value < value) {
    Insert(&(*e)->right, *e, value);
  } else {
    // (*e)->value == value
    assert((*e)->value != value);
  }

  //叶子节点处完成插入后，沿着父结点向上的每一个节点都需要检查是否满足平衡性，若不平衡则旋转
  //递归函数可以对每个节点*e在插入后进行检查

  Fix(*e);
}

static AvlNode *Next(AvlNode *e) {
  if (is_nil(e->right)) {
    return &AVLNIL;
  }
  AvlNode *next = e->right;
  while (not_nil(next->left)) {
    next = next->left;
  }
  return next;
}

static AvlNode *Prev(AvlNode *e) { return e->left; }

void AvlTreeErase(AvlTree *t, int value) {
  assert(not_nil(t->root));
  AvlNode *e = Find(t->root, value);
  assert(not_nil(e));

  AvlNode *fix;
  set_nil(fix);

  if (not_nil(e->right)) {
    //用后继节点next代替e

    AvlNode *next = Next(e);
    e->value = next->value;
    if (next->father->left == next) {
      next->father->left = next->right;
    } else if (next->father->right == next) {
      next->father->right = next->right;
    } else {
      assert(next->father->left != next && next->father->right != next);
    }
    next->right->father = next->father;
    delete next;
    fix = e;
  } else if (not_nil(e->left)) {

    AvlNode *prev = Prev(e);
    e->value = prev->value;
    e->left = prev->left;
    if (not_nil(e->left)) {
      e->left->father = e;
    }
    e->right = prev->right;
    if (not_nil(e->right)) {
      e->right->father = e;
    }
    delete prev;
    fix = e;
  } else {
    //直接删除叶子节点e

    if (not_nil(e->father)) {
      if (e->father->left == e) {
        set_nil(e->father->left);
      } else if (e->father->right == e) {
        set_nil(e->father->right);
      } else {
        assert(e->father->left != e && e->father->right != e);
      }
    } else {
      set_nil(t->root);
    }
    delete e;
    fix = e->father;
  }

  while (not_nil(fix)) {
    Fix(fix);
    fix = fix->father;
  }
}

AvlTree *AvlTreeNew() {
  AvlTree *t = new AvlTree();
  set_nil(t->root);
  return t;
}

void AvlTreeFree(AvlTree *t) {
  assert(t);
  Free(t->root);
  delete t;
}

void AvlTreeInsert(AvlTree *t, int value) {
  Insert(&(t->root), &AVLNIL, value);
}

AvlNode *AvlTreeFind(AvlTree *t, int value) { return Find(t->root, value); }

<commit_msg>fix erase the 'fix' pointer<commit_after>#include "AvlTree.h"
#include <algorithm>
#include <cassert>
#include <utility>

AvlNode AVLNIL = {-1, -1, &AVLNIL, &AVLNIL, &AVLNIL};

#define is_nil(e) ((e) == &AVLNIL)
#define not_nil(e) ((e) != &AVLNIL)
#define set_nil(e) ((e) = &AVLNIL)
#define get_height(left, right) (std::max((left)->height, (right)->height) + 1)

AvlNode::AvlNode() {
  value = -1;
  height = -1;
  set_nil(left);
  set_nil(right);
  set_nil(father);
}

AvlNode::AvlNode(int v, int h, AvlNode *l, AvlNode *r, AvlNode *f) {
  value = v;
  height = h;
  left = l;
  right = r;
  father = f;
}

static void Free(AvlNode *e) {
  if (is_nil(e))
    return;
  Free(e->left);
  Free(e->right);
  delete e;
}

// left left case
// right-rotate
static void LL(AvlNode **e) {
  AvlNode *p;

  p = (*e)->left;
  (*e)->left = p->right;
  p->right = (*e);

  (*e)->height = get_height((*e)->left, (*e)->right);
  p->height = get_height(p->left, *e);
  (*e) = p;
}

// right right case
// left-rotate
static void RR(AvlNode **e) {
  AvlNode *p;

  p = (*e)->right;
  (*e)->right = p->left;
  p->left = (*e);

  (*e)->height = get_height((*e)->left, (*e)->right);
  p->height = get_height(p->right, *e);
  (*e) = p;
}

// left right case
// left-rotate, right-rotate -> RR, LL
static void LR(AvlNode **e) {
  RR(&((*e)->left));
  LL(e);
}

// right left case
// right-rotate, left-rotate -> LL, RR
static void RL(AvlNode **e) {
  LL(&((*e)->right));
  RR(e);
}

static AvlNode *Find(AvlNode *e, int value) {
  if (is_nil(e)) {
    return &AVLNIL;
  }
  //二分查找
  if (e->value == value) {
    return e;
  } else if (e->value > value) {
    return Find(e->left, value);
  } else {
    return Find(e->right, value);
  }
}

static void Fix(AvlNode *e) {
  e->height = get_height(e->left, e->right);
  int factor = e->left->height - e->right->height;
  if (factor > 1 && e->left->value > e->value) {
    LL(&e);
  }
  if (factor < -1 && e->right->value < e->value) {
    RR(&e);
  }
  if (factor > 1 && e->left->value < e->value) {
    LR(&e);
  }
  if (factor < -1 && e->right->value > e->value) {
    RL(&e);
  }
}

static void Insert(AvlNode **e, AvlNode *father, int value) {
  assert(e);
  assert(father);

  if (is_nil(*e)) {
    // *e is nil
    *e = new AvlNode();
    set_nil((*e)->left);
    set_nil((*e)->right);
    (*e)->father = father;
    (*e)->value = value;
    (*e)->height = get_height((*e)->left, (*e)->right);
    return;
  }

  //利用二分查找找到适合value插入的位置e

  if ((*e)->value > value) {
    Insert(&(*e)->left, *e, value);
  } else if ((*e)->value < value) {
    Insert(&(*e)->right, *e, value);
  } else {
    // (*e)->value == value
    assert((*e)->value != value);
  }

  //叶子节点处完成插入后，沿着父结点向上的每一个节点都需要检查是否满足平衡性，若不平衡则旋转
  //递归函数可以对每个节点*e在插入后进行检查

  Fix(*e);
}

static AvlNode *Next(AvlNode *e) {
  if (is_nil(e->right)) {
    return &AVLNIL;
  }
  AvlNode *next = e->right;
  while (not_nil(next->left)) {
    next = next->left;
  }
  return next;
}

static AvlNode *Prev(AvlNode *e) { return e->left; }

void AvlTreeErase(AvlTree *t, int value) {
  assert(not_nil(t->root));
  AvlNode *e = Find(t->root, value);
  assert(not_nil(e));

  AvlNode *fix;
  set_nil(fix);

  if (not_nil(e->right)) {
    //用后继节点next代替e

    AvlNode *next = Next(e);
    e->value = next->value;
    if (next->father->left == next) {
      next->father->left = next->right;
    } else if (next->father->right == next) {
      next->father->right = next->right;
    } else {
      assert(next->father->left != next && next->father->right != next);
    }
    next->right->father = next->father;
    delete next;
    fix = e;
  } else if (not_nil(e->left)) {

    AvlNode *prev = Prev(e);
    e->value = prev->value;
    e->left = prev->left;
    if (not_nil(e->left)) {
      e->left->father = e;
    }
    e->right = prev->right;
    if (not_nil(e->right)) {
      e->right->father = e;
    }
    delete prev;
    fix = e;
  } else {
    //直接删除叶子节点e

    if (not_nil(e->father)) {
      if (e->father->left == e) {
        set_nil(e->father->left);
      } else if (e->father->right == e) {
        set_nil(e->father->right);
      } else {
        assert(e->father->left != e && e->father->right != e);
      }
    } else {
      set_nil(t->root);
    }
    fix = e->father;
    delete e;
  }

  while (not_nil(fix)) {
    Fix(fix);
    fix = fix->father;
  }
}

AvlTree *AvlTreeNew() {
  AvlTree *t = new AvlTree();
  set_nil(t->root);
  return t;
}

void AvlTreeFree(AvlTree *t) {
  assert(t);
  Free(t->root);
  delete t;
}

void AvlTreeInsert(AvlTree *t, int value) {
  Insert(&(t->root), &AVLNIL, value);
}

AvlNode *AvlTreeFind(AvlTree *t, int value) { return Find(t->root, value); }

<|endoftext|>


<commit_before>#include <Dpdk/DpdkNetInterface.h>
#include <Packet.h>
#include <string.h>

extern "C"
{
#include <rte_config.h>
#include <rte_common.h>
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
}

namespace nshdev
{

constexpr size_t MAX_PKT_BURST = 32;

struct EtherOriginInfo: public OriginInfo
{
    struct rte_mbuf *mbuf;
    struct ether_hdr hdr;
};

PacketRef MbufToPacketRef(struct rte_mbuf& mbuf,
                          struct EtherOriginInfo& info)
{

    struct ether_hdr *ether = rte_pktmbuf_mtod(&mbuf, struct ether_hdr *);

    info.mbuf = &mbuf;
    memcpy(&info.hdr, ether, sizeof(struct ether_hdr));

    char *adjPkt = rte_pktmbuf_adj(&mbuf, sizeof(struct ether_hdr));

    return PacketRef(reinterpret_cast<uint8_t*>(adjPkt),
                     rte_pktmbuf_pkt_len(&mbuf),
                     &info);
}

DpdkNetInterface::DpdkNetInterface(uint8_t portId):
    m_portId(portId)
{
}

int DpdkNetInterface::GetWaitFD() const
{
    // do not wait -- poll via run
    return -1;
}

void DpdkNetInterface::Run()
{
    struct rte_mbuf *pkts_burst[MAX_PKT_BURST];

    uint32_t numPackets = rte_eth_rx_burst(m_portId,
                                           m_rxQueueId,
                                           pkts_burst,
                                           MAX_PKT_BURST);
    EtherOriginInfo info;
    for(uint32_t i=0; i < numPackets; ++i)
    {
        PacketRef ref = MbufToPacketRef(*pkts_burst[i], info);

        // this will fail if we couldn't prepend
        if(ref.Data() != nullptr)
        {
            Forward(ref);
        }
        else
        {
            m_failedMbufCreations++;
        }
    }
}

void DpdkNetInterface::ReturnToSender(PacketRef& packetRef)
{
    const EtherOriginInfo &info = static_cast<const EtherOriginInfo&>(*packetRef.From());

    struct rte_mbuf *toSend = info.mbuf;

    // add on an ethernet header and swap the cached addresses
    char *pkt = rte_pktmbuf_prepend(toSend, sizeof(struct ether_hdr));

    if(pkt == 0)
    {
        // Sadness. No room. :(
        m_numFailedPrepend++;
        rte_pktmbuf_free(toSend);
        return;
    }

    struct ether_hdr &toSendHdr = reinterpret_cast<struct ether_hdr&>(*pkt);
    ether_addr_copy(&info.hdr.s_addr, &toSendHdr.d_addr);
    ether_addr_copy(&info.hdr.d_addr, &toSendHdr.s_addr);
    toSendHdr.ether_type = info.hdr.ether_type;

    // Sending one at a time is not the most efficient, but without changes to
    // how things are scheduled, it's all we can do.
    uint16_t numTx = rte_eth_tx_burst(m_portId,
                                      m_txQueueId,
                                      &toSend,
                                      1);
    if(numTx < 1)
    {
        // Full! How dare you!
        m_numOutDiscards++;
        rte_pktmbuf_free(info.mbuf);
        return;
    }
}

}
<commit_msg>Make dpdk run loop run as long as it has packets<commit_after>#include <Dpdk/DpdkNetInterface.h>
#include <Packet.h>
#include <string.h>

extern "C"
{
#include <rte_config.h>
#include <rte_common.h>
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
}

namespace nshdev
{

constexpr size_t MAX_PKT_BURST = 32;

struct EtherOriginInfo: public OriginInfo
{
    struct rte_mbuf *mbuf;
    struct ether_hdr hdr;
};

PacketRef MbufToPacketRef(struct rte_mbuf& mbuf,
                          struct EtherOriginInfo& info)
{

    struct ether_hdr *ether = rte_pktmbuf_mtod(&mbuf, struct ether_hdr *);

    info.mbuf = &mbuf;
    memcpy(&info.hdr, ether, sizeof(struct ether_hdr));

    char *adjPkt = rte_pktmbuf_adj(&mbuf, sizeof(struct ether_hdr));

    return PacketRef(reinterpret_cast<uint8_t*>(adjPkt),
                     rte_pktmbuf_pkt_len(&mbuf),
                     &info);
}

DpdkNetInterface::DpdkNetInterface(uint8_t portId):
    m_portId(portId)
{
}

int DpdkNetInterface::GetWaitFD() const
{
    // do not wait -- poll via run
    return -1;
}

void DpdkNetInterface::Run()
{
    struct rte_mbuf *pkts_burst[MAX_PKT_BURST];

    uint32_t numPackets = 0;

    do
    {
        numPackets = rte_eth_rx_burst(m_portId,
                                      m_rxQueueId,
                                      pkts_burst,
                                      MAX_PKT_BURST);
        EtherOriginInfo info;
        for(uint32_t i=0; i < numPackets; ++i)
        {
            PacketRef ref = MbufToPacketRef(*pkts_burst[i], info);

            // this will fail if we couldn't prepend
            if(ref.Data() != nullptr)
            {
                Forward(ref);
            }
            else
            {
                m_failedMbufCreations++;
            }
        }
    }
    while (numPackets > 0);
}

void DpdkNetInterface::ReturnToSender(PacketRef& packetRef)
{
    const EtherOriginInfo &info = static_cast<const EtherOriginInfo&>(*packetRef.From());

    struct rte_mbuf *toSend = info.mbuf;

    // add on an ethernet header and swap the cached addresses
    char *pkt = rte_pktmbuf_prepend(toSend, sizeof(struct ether_hdr));

    if(pkt == 0)
    {
        // Sadness. No room. :(
        m_numFailedPrepend++;
        rte_pktmbuf_free(toSend);
        return;
    }

    struct ether_hdr &toSendHdr = reinterpret_cast<struct ether_hdr&>(*pkt);
    ether_addr_copy(&info.hdr.s_addr, &toSendHdr.d_addr);
    ether_addr_copy(&info.hdr.d_addr, &toSendHdr.s_addr);
    toSendHdr.ether_type = info.hdr.ether_type;

    // Sending one at a time is not the most efficient, but without changes to
    // how things are scheduled, it's all we can do.
    uint16_t numTx = rte_eth_tx_burst(m_portId,
                                      m_txQueueId,
                                      &toSend,
                                      1);
    if(numTx < 1)
    {
        // Full! How dare you!
        m_numOutDiscards++;
        rte_pktmbuf_free(info.mbuf);
        return;
    }
}

}
<|endoftext|>