<commit_before>/**
 *  Copyright 2014-2016 CyberVision, Inc.
 *
 *  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 <memory>

#include <kaa/Kaa.hpp>
#include <kaa/logging/Log.hpp>
#include <kaa/logging/LoggingUtils.hpp>
#include <kaa/notification/INotificationTopicListListener.hpp>
#include <kaa/common/exception/UnavailableTopicException.hpp>

using namespace kaa;

static void showTopicList(const Topics& topics)
{
    if (topics.empty()) {
        std::cout << "Topic list is empty" << std::endl;
    } else {
        for (const auto& topic : topics) {
            std::cout << (boost::format("Topic: id '%1%', name '%2%', type '%3%'")
                % topic.id % topic.name % LoggingUtils::TopicSubscriptionTypeToString(topic.subscriptionType)) << std::endl;
        }
    }
}

static std::list<std::string> extractOptionalTopicIds(const Topics& topics) {
    std::list<std::string> topicIds;
    for (const auto& topic : topics) {
        if (topic.subscriptionType == SubscriptionType::OPTIONAL_SUBSCRIPTION) {
            topicIds.push_back(topic.id);
        }
    }
    return topicIds;
}

// The listener which receives notifications on topics.
class BasicNotificationListener : public INotificationListener {
public:
    virtual void onNotification(const std::string& topicId, const KaaNotification& notification)
    {
        std::cout << (boost::format("Notification for topic id '%1%' received") % topicId) << std::endl;
        std::cout << (boost::format("Notification body: '%1%'")
            % (notification.message.is_null() ? "" : notification.message.get_string())) << std::endl;
    }
};

// A listener that tracks the notification topic list updates
// and subscribes the Kaa client to every new topic available.
class BasicNotificationTopicListListener : public INotificationTopicListListener {
public:
    BasicNotificationTopicListListener(IKaaClient& kaaClient) : kaaClient_(kaaClient) {}

    virtual void onListUpdated(const Topics& topics)
    {
        std::cout << ("Topic list was updated") << std::endl;
        showTopicList(topics);

        try {
            auto optionalTopicIds = extractOptionalTopicIds(topics);
            for (const auto& id : optionalTopicIds) {
                std::cout << (boost::format("Subscribing to optional topic '%1%'") % id) << std::endl;
            }

            kaaClient_.subscribeToTopics(optionalTopicIds);
        } catch (UnavailableTopicException& e) {
            std::cout << (boost::format("Topic is unavailable, can't subscribe: %1%") % e.what()) << std::endl;
        }
    }

private:
    IKaaClient&    kaaClient_;
};

int main()
{
    std::cout << "Notification demo started" << std::endl;
    std::cout << "--= Press Enter to exit =--" << std::endl;

    /*
     * Initialize the Kaa endpoint.
     */
    auto kaaClient = Kaa::newClient();

    /*
     * Add the listener which receives the list of available topics.
     */
    std::unique_ptr<INotificationTopicListListener> topicListListener(new BasicNotificationTopicListListener(*kaaClient));
    kaaClient->addTopicListListener(*topicListListener);

    /*
     * Add the listener which receives notifications on all topics.
     */
    std::unique_ptr<INotificationListener> commonNotificationListener(new BasicNotificationListener);
    kaaClient->addNotificationListener(*commonNotificationListener);

    /*
     * Run the Kaa endpoint.
     */
    kaaClient->start();

    /*
     * Get available notification topics.
     */
    auto availableTopics = kaaClient->getTopics();

    /*
     * List the obtained notification topics.
     */
    showTopicList(availableTopics);

    /*
     * Wait for the Enter key before exiting.
     */
    std::cin.get();

    /*
     * Remove the listener which receives the list of available topics.
     */
    kaaClient->removeTopicListListener(*topicListListener);

    /*
     * Stop the Kaa endpoint.
     */
    kaaClient->stop();

    std::cout << "Notification demo stopped" << std::endl;

    return 0;
}
<commit_msg>KAA-825: Fix notification demo according to the latest changes<commit_after>/**
 *  Copyright 2014-2016 CyberVision, Inc.
 *
 *  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 <memory>

#include <kaa/Kaa.hpp>
#include <kaa/logging/Log.hpp>
#include <kaa/logging/LoggingUtils.hpp>
#include <kaa/notification/INotificationTopicListListener.hpp>
#include <kaa/common/exception/UnavailableTopicException.hpp>

using namespace kaa;

static void showTopicList(const Topics& topics)
{
    if (topics.empty()) {
        std::cout << "Topic list is empty" << std::endl;
    } else {
        for (const auto& topic : topics) {
            std::cout << (boost::format("Topic: id '%1%', name '%2%', type '%3%'")
                % topic.id % topic.name % LoggingUtils::TopicSubscriptionTypeToString(topic.subscriptionType)) << std::endl;
        }
    }
}

static std::list<std::int64_t> extractOptionalTopicIds(const Topics& topics) {
    std::list<std::int64_t> topicIds;
    for (const auto& topic : topics) {
        if (topic.subscriptionType == SubscriptionType::OPTIONAL_SUBSCRIPTION) {
            topicIds.push_back(topic.id);
        }
    }
    return topicIds;
}

// The listener which receives notifications on topics.
class BasicNotificationListener : public INotificationListener {
public:
    virtual void onNotification(const std::int64_t topicId, const KaaNotification& notification)
    {
        std::cout << (boost::format("Notification for topic id '%1%' received") % topicId) << std::endl;
        std::cout << (boost::format("Notification body: '%1%'")
            % (notification.message.is_null() ? "" : notification.message.get_string())) << std::endl;
    }
};

// A listener that tracks the notification topic list updates
// and subscribes the Kaa client to every new topic available.
class BasicNotificationTopicListListener : public INotificationTopicListListener {
public:
    BasicNotificationTopicListListener(IKaaClient& kaaClient) : kaaClient_(kaaClient) {}

    virtual void onListUpdated(const Topics& topics)
    {
        std::cout << ("Topic list was updated") << std::endl;
        showTopicList(topics);

        try {
            auto optionalTopicIds = extractOptionalTopicIds(topics);
            for (const auto& id : optionalTopicIds) {
                std::cout << (boost::format("Subscribing to optional topic '%1%'") % id) << std::endl;
            }

            kaaClient_.subscribeToTopics(optionalTopicIds);
        } catch (UnavailableTopicException& e) {
            std::cout << (boost::format("Topic is unavailable, can't subscribe: %1%") % e.what()) << std::endl;
        }
    }

private:
    IKaaClient&    kaaClient_;
};

int main()
{
    std::cout << "Notification demo started" << std::endl;
    std::cout << "--= Press Enter to exit =--" << std::endl;

    /*
     * Initialize the Kaa endpoint.
     */
    auto kaaClient = Kaa::newClient();

    /*
     * Add the listener which receives the list of available topics.
     */
    std::unique_ptr<INotificationTopicListListener> topicListListener(new BasicNotificationTopicListListener(*kaaClient));
    kaaClient->addTopicListListener(*topicListListener);

    /*
     * Add the listener which receives notifications on all topics.
     */
    std::unique_ptr<INotificationListener> commonNotificationListener(new BasicNotificationListener);
    kaaClient->addNotificationListener(*commonNotificationListener);

    /*
     * Run the Kaa endpoint.
     */
    kaaClient->start();

    /*
     * Get available notification topics.
     */
    auto availableTopics = kaaClient->getTopics();

    /*
     * List the obtained notification topics.
     */
    showTopicList(availableTopics);

    /*
     * Wait for the Enter key before exiting.
     */
    std::cin.get();

    /*
     * Remove the listener which receives the list of available topics.
     */
    kaaClient->removeTopicListListener(*topicListListener);

    /*
     * Stop the Kaa endpoint.
     */
    kaaClient->stop();

    std::cout << "Notification demo stopped" << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012,2013 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */

#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/timing.h"
#include "config/usart.h"
#include "config/string.h"

using namespace stm32plus;

/**
 * Timer input capture demo.
 *
 * This demonstration will calculate the frequency of a
 * PWM signal and write it out to USART1 every 3 seconds.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Uart4.
 *
 * The USART protocol is 57600/8/N/1
 *
 * Timer5 channel 4 is used to generate a 100KHz PWM
 * signal. This signal is fed to Timer3 channel 3. Each
 * rising edge of the signal causes an interrupt to fire.
 * When two successive edges have been captured we
 * calculate and display the result.
 *
 * You will need to wire PA3 to PB0 to test this demo.
 *
 * Compatible MCU:
 *   STM32F1
 *   STM32F4
 *
 * Tested on devices:
 *   STM32F103ZET6
 *   STM32F407VGT6
 */

class TimerInputCaptureTest {

  protected:

    /**
     * Declare a type for our input timer.
     */

    typedef Timer3<
        Timer3InternalClockFeature,       // we'll need this for the frequency calculation
        TimerChannel3Feature,             // we're going to use channel 3
        Timer3InterruptFeature,           // we want to use interrupts
        Timer3GpioFeature<                // we want to read something from GPIO
          TIMER_REMAP_NONE,               // the GPIO input will not be remapped
          TIM3_CH3_IN                     // we will read channel 3 from GPIO PB0
        >
      > MyInputTimer;

    /*
     * The timer needs to be a class member so we can see it from the Observable callback
     */

    MyInputTimer *_myInputTimer;

    /*
     * State variables for reading the frequency
     */

    volatile uint16_t _captures[2];
    volatile uint8_t _captureIndex;
    volatile uint32_t _capturedFrequency;
    volatile bool _capturingNextFrequency;

  public:

    void run() {

      /*
       * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
       * if your application demands that you use the alternate pins for USART1
       */

      Usart1<> usart1(57600);

      /*
       * We'll use an output stream for sending to the port instead of using the
       * send(uint8_t) method on the usart object
       */

      UsartPollingOutputStream outputStream(usart1);

      /*
       * We'll use Timer 5 to generate a PWM signal on its channel 4.
       * The signal will be output on PA3
       */

      Timer5<
        Timer5InternalClockFeature,     // clocked from the internal clock
        TimerChannel4Feature,           // we're going to use channel 4
        Timer5GpioFeature<              // we want to output something to GPIO
          TIMER_REMAP_NONE,             // the GPIO output will not (cannot for this timer) be remapped
          TIM5_CH4_OUT                  // we will output channel 4 to GPIO (PA3)
        >
      > outputTimer;

      /*
       * Set the output timer to 24Mhz with a reload frequency of 100Khz (24Mhz/240).
       */

      outputTimer.setTimeBaseByFrequency(24000000,240-1);

      /*
       * Initialise the output channel for PWM output with a duty cycle of 50%. This will
       * give us a nice square wave for the input capture channel to sample.
       */

      outputTimer.initCompareForPwmOutput(50);

      /*
       * Declare a new instance of the input capture timer.
       */

      _myInputTimer=new MyInputTimer;

      /*
       * Insert our subscribtion of the capture interrupts generated by the input timer
       */

      _myInputTimer->TimerInterruptEventSender.insertSubscriber(
          TimerInterruptEventSourceSlot::bind(this,&TimerInputCaptureTest::onInterrupt)
        );

      /*
       * Initialise the channel (this will be channel 2) for capturing the signal
       */

      _myInputTimer->initCapture(
          TIM_ICPolarity_Rising,      // capture rising edges
          TIM_ICSelection_DirectTI,   // direct connection to timer input trigger
          TIM_ICPSC_DIV1,             // sample every transition
          0,                          // no oversampling filter
          0);                         // prescaler of 0

      /*
       * Reset the variables used to hold the state
       */

      _captureIndex=0;
      _capturingNextFrequency=true;

      /*
       * Enable channel 3 interrupts on Timer 3.
       */

      _myInputTimer->enableInterrupts(TIM_IT_CC3);

      /*
       * Enable both timers to start the action
       */

      outputTimer.enablePeripheral();
      _myInputTimer->enablePeripheral();

      /*
       * Loop until the next frequency has been captured
       */

      for(;;) {

        while(_capturingNextFrequency);

        /*
         * Write out the captured frequency to the USART
         */

        char buf[15];
        StringUtil::modp_uitoa10(_capturedFrequency,buf);
        outputStream << buf << "Hz\r\n";

        /*
         * Pause for 3 seconds
         */

        MillisecondTimer::delay(3000);

        /*
         * start capturing again
         */

        _capturingNextFrequency=true;
      }
    }

    /*
     * Interrupt callback function. This is called when the input capture
     * event is fired
     */

    void onInterrupt(TimerEventType tet,uint8_t /* timerNumber */) {

      if(tet==TimerEventType::EVENT_COMPARE3) {

        // store the current capture time

        _captures[_captureIndex]=_myInputTimer->getCapture();

        if(_captureIndex++==1) {

          // if the main loop is ready then calc the frequency and signal the main loop
          // note the scaling divisor because our timer clocks are scaled by a factor of
          // the APB1 prescaler.

          if(_capturingNextFrequency) {
            _capturedFrequency=_myInputTimer->calculateFrequency(_captures[0],_captures[1]);
            _capturingNextFrequency=false;
          }

          // back to storing at position zero

          _captureIndex=0;
        }
      }
    }
};

/*
 * Main entry point
 */

int main() {

  // we're using interrupts, initialise NVIC

  Nvic::initialise();

  // initialise the SysTick timer

  MillisecondTimer::initialise();

  TimerInputCaptureTest test;
  test.run();

  // not reached
  return 0;
}
<commit_msg>timer_input_capture reworked slightly to cater for vl<commit_after>/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012,2013 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */

#include "config/stm32plus.h"
#include "config/timer.h"
#include "config/timing.h"
#include "config/usart.h"
#include "config/string.h"

using namespace stm32plus;

/**
 * Timer input capture demo.
 *
 * This demonstration will calculate the frequency of a
 * PWM signal and write it out to USART1 every 3 seconds.
 *
 * Note that if you are using the STM32F4DISCOVERY board
 * then you cannot use Usart1 since the pins clash with
 * onboard peripherals. I have tested this code on that
 * board using Uart4.
 *
 * The USART protocol is 57600/8/N/1
 *
 * Timer4 channel 1 is used to generate a PWM
 * signal. This signal is fed to Timer3 channel 3. Each
 * rising edge of the signal causes an interrupt to fire.
 * When two successive edges have been captured we
 * calculate and display the result.
 *
 * On the F4 and F103 HD the frequency is 100KHz. This is too
 * fast for the F100 VL so we use 10KHz instead.
 *
 * You will need to wire PB6 to PB0 to test this demo.
 *
 * Compatible MCU:
 *   STM32F1
 *   STM32F4
 *
 * Tested on devices:
 *   STM32F100RBT6
 *   STM32F103ZET6
 *   STM32F407VGT6
 */

class TimerInputCaptureTest {

  protected:

    /**
     * Declare a type for our input timer.
     */

    typedef Timer3<
        Timer3InternalClockFeature,       // we'll need this for the frequency calculation
        TimerChannel3Feature,             // we're going to use channel 3
        Timer3InterruptFeature,           // we want to use interrupts
        Timer3GpioFeature<                // we want to read something from GPIO
          TIMER_REMAP_NONE,               // the GPIO input will not be remapped
          TIM3_CH3_IN                     // we will read channel 3 from GPIO PB0
        >
      > MyInputTimer;

    /*
     * The timer needs to be a class member so we can see it from the Observable callback
     */

    MyInputTimer *_myInputTimer;

    /*
     * State variables for reading the frequency
     */

    volatile uint16_t _captures[2];
    volatile uint8_t _captureIndex;
    volatile uint32_t _capturedFrequency;
    volatile bool _capturingNextFrequency;

  public:

    void run() {

      /*
       * Declare a USART1 object. Note that an alternative Usart1_Remap object is available
       * if your application demands that you use the alternate pins for USART1
       */

      Usart1<> usart1(57600);

      /*
       * We'll use an output stream for sending to the port instead of using the
       * send(uint8_t) method on the usart object
       */

      UsartPollingOutputStream outputStream(usart1);

      /*
       * We'll use Timer 4 to generate a PWM signal on its channel 1.
       * The signal will be output on PB6
       */

      Timer4<
        Timer4InternalClockFeature,     // clocked from the internal clock
        TimerChannel1Feature,           // we're going to use channel 1
        Timer4GpioFeature<              // we want to output something to GPIO
          TIMER_REMAP_NONE,             // the GPIO output will not (cannot for this timer) be remapped
          TIM4_CH1_OUT                  // we will output channel 1 to GPIO (PB6)
        >
      > outputTimer;

      /*
       * On the F1HD and F4 we set the output timer to 24Mhz with a reload frequency of 100Khz (24Mhz/240).
       * On the F1 VL we set it to 10KHz to avoid CPU starvation by the interrupt handler.
       */

#if defined(STM32PLUS_F1_MD_VL)
      outputTimer.setTimeBaseByFrequency(800000,80-1);
#else
      outputTimer.setTimeBaseByFrequency(24000000,240-1);
#endif

      /*
       * Initialise the output channel for PWM output with a duty cycle of 50%. This will
       * give us a nice square wave for the input capture channel to sample.
       */

      outputTimer.initCompareForPwmOutput(50);

      /*
       * Declare a new instance of the input capture timer.
       */

      _myInputTimer=new MyInputTimer;

      /*
       * Insert our subscribtion of the capture interrupts generated by the input timer
       */

      _myInputTimer->TimerInterruptEventSender.insertSubscriber(
          TimerInterruptEventSourceSlot::bind(this,&TimerInputCaptureTest::onInterrupt)
        );

      /*
       * Initialise the channel (this will be channel 2) for capturing the signal
       */

      _myInputTimer->initCapture(
          TIM_ICPolarity_Rising,      // capture rising edges
          TIM_ICSelection_DirectTI,   // direct connection to timer input trigger
          TIM_ICPSC_DIV1,             // sample every transition
          0,                          // no oversampling filter
          0);                         // prescaler of 0

      /*
       * Reset the variables used to hold the state
       */

      _captureIndex=0;
      _capturingNextFrequency=true;

      /*
       * Enable channel 3 interrupts on Timer 3.
       */

      _myInputTimer->enableInterrupts(TIM_IT_CC3);

      /*
       * Enable both timers to start the action
       */

      outputTimer.enablePeripheral();
      _myInputTimer->enablePeripheral();

      /*
       * Loop until the next frequency has been captured
       */

      for(;;) {

        while(_capturingNextFrequency);

        /*
         * Write out the captured frequency to the USART
         */

        char buf[15];
        StringUtil::modp_uitoa10(_capturedFrequency,buf);
        outputStream << buf << "Hz\r\n";

        /*
         * Pause for 3 seconds
         */

        MillisecondTimer::delay(3000);

        /*
         * start capturing again
         */

        _capturingNextFrequency=true;
      }
    }

    /*
     * Interrupt callback function. This is called when the input capture
     * event is fired
     */

    void onInterrupt(TimerEventType tet,uint8_t /* timerNumber */) {

      if(tet==TimerEventType::EVENT_COMPARE3) {

        // store the current capture time

        _captures[_captureIndex]=_myInputTimer->getCapture();

        if(_captureIndex++==1) {

          // if the main loop is ready then calc the frequency and signal the main loop
          // note the scaling divisor because our timer clocks are scaled by a factor of
          // the APB1 prescaler.

          if(_capturingNextFrequency) {
            _capturedFrequency=_myInputTimer->calculateFrequency(_captures[0],_captures[1]);
            _capturingNextFrequency=false;
          }

          // back to storing at position zero

          _captureIndex=0;
        }
      }
    }
};

/*
 * Main entry point
 */

int main() {

  // we're using interrupts, initialise NVIC

  Nvic::initialise();

  // initialise the SysTick timer

  MillisecondTimer::initialise();

  TimerInputCaptureTest test;
  test.run();

  // not reached
  return 0;
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <glog/logging.h>
#include "netlink/tap_manager.hpp"
#include "utils.hpp"

namespace basebox {

static inline void
release_packets(std::deque<std::pair<int, basebox::packet *>> &q) {
  for (auto i : q) {
    std::free(i.second);
  }
}

tap_io::~tap_io() { thread.stop(); }

void tap_io::register_tap(int fd, uint32_t port_id, switch_callback &cb) {
  {
    std::lock_guard<std::mutex> guard(events_mutex);
    events.emplace_back(std::make_tuple(TAP_IO_ADD, fd, port_id, &cb));
  }

  thread.wakeup();
}

void tap_io::unregister_tap(int fd, uint32_t port_id) {
  {
    std::lock_guard<std::mutex> guard(events_mutex);
    events.emplace_back(std::make_tuple(TAP_IO_REM, fd, port_id, nullptr));
  }

  thread.wakeup();
}

void tap_io::enqueue(int fd, basebox::packet *pkt) {
  if (fd == -1) {
    std::free(pkt);
    return;
  }

  {
    // store pkt in outgoing queue
    std::lock_guard<std::mutex> guard(pout_queue_mutex);
    pout_queue.emplace_back(std::make_pair(fd, pkt));
  }
  thread.wakeup();
}

void tap_io::handle_read_event(rofl::cthread &thread, int fd) {
  basebox::packet *pkt =
      (basebox::packet *)std::malloc(sizeof(basebox::packet));

  if (pkt == nullptr)
    return;

  pkt->len = read(fd, pkt->data, basebox::packet_data_len);

  if (pkt->len > 0) {
    VLOG(3) << __FUNCTION__ << ": read " << pkt->len << " bytes from fd=" << fd
            << " into pkt=" << pkt << " tid=" << pthread_self();
    std::pair<uint32_t, switch_callback *> &cb = sw_cbs.at(fd);
    cb.second->enqueue_to_switch(cb.first, pkt);
  } else {
    // error occured (or non-blocking)
    switch (errno) {
    case EAGAIN:
      LOG(ERROR) << __FUNCTION__
                 << ": EAGAIN XXX not implemented packet is dropped";
      std::free(pkt);
    default:
      LOG(ERROR) << __FUNCTION__ << ": unknown error occured";
      std::free(pkt);
    }
  }
}

void tap_io::handle_write_event(rofl::cthread &thread, int fd) {
  thread.drop_write_fd(fd);
  tx();
}

void tap_io::tx() {
  std::pair<int, basebox::packet *> pkt;
  std::deque<std::pair<int, basebox::packet *>> out_queue;

  {
    std::lock_guard<std::mutex> guard(pout_queue_mutex);
    std::swap(out_queue, pout_queue);
  }

  while (not out_queue.empty()) {

    pkt = out_queue.front();
    int rc = 0;
    if ((rc = write(pkt.first, pkt.second->data, pkt.second->len)) < 0) {
      switch (errno) {
      case EAGAIN:
        VLOG(1) << __FUNCTION__ << ": EAGAIN";
        {
          std::lock_guard<std::mutex> guard(pout_queue_mutex);
          std::move(out_queue.rbegin(), out_queue.rend(),
                    std::front_inserter(pout_queue));
        }
        thread.add_write_fd(pkt.first, true, false);
        return;
      case EIO:
        // tap not enabled drop packet
        VLOG(1) << __FUNCTION__ << ": EIO";
        release_packets(out_queue);
        return;
      default:
        // will drop packets
        release_packets(out_queue);
        LOG(ERROR) << __FUNCTION__ << ": unknown error occurred rc=" << rc
                   << " errno=" << errno << " '" << strerror(errno);
        return;
      }
    }
    std::free(pkt.second);
    out_queue.pop_front();
  }
}

void tap_io::handle_events() {
  std::lock_guard<std::mutex> guard(events_mutex);

  // register fds
  for (auto ev : events) {
    int fd = std::get<1>(ev);
    switch (std::get<0>(ev)) {

    case TAP_IO_ADD:
      sw_cbs.emplace(
          std::make_pair(fd, std::make_pair(std::get<2>(ev), std::get<3>(ev))));
      thread.add_read_fd(fd, true, false);
      break;
    case TAP_IO_REM:
      thread.drop_fd(fd, false);
      sw_cbs.erase(fd);
      break;
    default:
      break;
    }
  }
  events.clear();
}

tap_manager::~tap_manager() { destroy_tapdevs(); }

int tap_manager::create_tapdev(uint32_t port_id, const std::string &port_name,
                               switch_callback &cb) {
  int r = 0;
  bool dev_exists = false;
  bool dev_name_exists = false;
  auto dev_it = tap_devs.find(port_id);

  if (dev_it != tap_devs.end())
    dev_exists = true;

  {
    std::lock_guard<std::mutex> lock{rp_mutex};
    auto dev_name_it = tap_names.find(port_name);

    if (dev_name_it != tap_names.end())
      dev_name_exists = true;
  }

  if (!dev_exists && !dev_name_exists) {
    // create a new tap device

    ctapdev *dev;
    try {
      dev = new ctapdev(port_name);
      tap_devs.insert(std::make_pair(port_id, dev));
      {
        std::lock_guard<std::mutex> lock{rp_mutex};
        tap_names.insert(std::make_pair(port_name, port_id));
      }

      // create the port
      dev->tap_open();
      int fd = dev->get_fd();

      LOG(INFO) << __FUNCTION__ << ": port_id=" << port_id
                << " portname=" << port_name << " fd=" << fd << " ptr=" << dev;

      // start reading from port
      io.register_tap(fd, port_id, cb);

    } catch (std::exception &e) {
      LOG(ERROR) << __FUNCTION__ << ": failed to create tapdev " << port_name;
      r = -EINVAL;
    }
  } else {
    LOG(INFO) << __FUNCTION__ << ": " << port_name
              << " with port_id=" << port_id << " already existing";
  }
  return r;
}

int tap_manager::destroy_tapdev(uint32_t port_id,
                                const std::string &port_name) {
  auto it = tap_devs.find(port_id);
  if (it == tap_devs.end()) {
    LOG(WARNING) << __FUNCTION__ << ": called for invalid port_id=" << port_id
                 << " port_name=" << port_name;
    return 0;
  }

  // drop port from name mapping
  std::lock_guard<std::mutex> lock{rp_mutex};
  port_deleted.push_back(port_id);
  auto tap_names_it = tap_names.find(port_name);

  if (tap_names_it != tap_names.end()) {
    tap_names.erase(tap_names_it);
  }

  // drop port from port mapping
  auto dev = it->second;
  int fd = dev->get_fd();
  tap_devs.erase(it);
  delete dev;

  // XXX check if previous to delete
  io.unregister_tap(fd, port_id);

  return 0;
}

void tap_manager::destroy_tapdevs() {
  std::map<uint32_t, ctapdev *> ddevs;
  ddevs.swap(tap_devs);
  for (auto &dev : ddevs) {
    delete dev.second;
  }
  tap_names.clear();
}

int tap_manager::enqueue(uint32_t port_id, basebox::packet *pkt) {
  try {
    int fd = tap_devs.at(port_id)->get_fd();
    io.enqueue(fd, pkt);
  } catch (std::exception &e) {
    LOG(ERROR) << __FUNCTION__ << ": failed to enqueue packet " << pkt
               << " to port_id=" << port_id;
    std::free(pkt);
  }
  return 0;
}

void tap_manager::tap_dev_ready(int ifindex, const std::string &name) {
  auto it = ifindex_to_id.find(ifindex);
  if (it != ifindex_to_id.end())
    return;

  std::lock_guard<std::mutex> lock{rp_mutex};
  auto tn_it = tap_names.find(name);

  if (tn_it == tap_names.end()) {
    LOG(WARNING) << __FUNCTION__ << "invalid port name " << name;
    return;
  }

  // update maps
  auto id2ifi_it = id_to_ifindex.insert(std::make_pair(tn_it->second, ifindex));
  if (!id2ifi_it.second && id2ifi_it.first->second != ifindex) {
    // update only if the ifindex has changed
    LOG(WARNING) << __FUNCTION__
                 << ": enforced update of id:ifindex mapping id="
                 << id2ifi_it.first->first
                 << " ifindex(old) = " << id2ifi_it.first->second
                 << " ifindex(new)=" << ifindex;

    // remove overwritten index in ifindex_to_id map
    auto it = ifindex_to_id.find(id2ifi_it.first->second);
    if (it != ifindex_to_id.end()) {
      ifindex_to_id.erase(it);
    }

    // update the old one
    id2ifi_it.first->second = ifindex;
  }

  auto rv1 = ifindex_to_id.insert(std::make_pair(ifindex, tn_it->second));
  if (!rv1.second && rv1.first->second != tn_it->second) {
    // update only if the id has changed
    LOG(WARNING) << __FUNCTION__
                 << ": enforced update of ifindex:id mapping ifindex="
                 << ifindex << " id(old)=" << rv1.first->second
                 << " id(new)=" << tn_it->second;
    rv1.first->second = tn_it->second;
  }
}

void tap_manager::tap_dev_removed(int ifindex) {
  std::lock_guard<std::mutex> lock{rp_mutex};

  auto ifi2id_it = ifindex_to_id.find(ifindex);
  if (ifi2id_it == ifindex_to_id.end()) {
    VLOG(2) << __FUNCTION__
            << ": ignore removal of tap device with ifindex=" << ifindex;
    return;
  }

  // check if this port was scheduled for deletion
  auto pd_it =
      std::find(port_deleted.begin(), port_deleted.end(), ifi2id_it->second);
  if (pd_it == port_deleted.end()) {
    auto pn_it = tap_devs.find(ifi2id_it->second);
    LOG(FATAL) << __FUNCTION__ << ": illegal removal of port "
               << pn_it->second->get_devname() << " with ifindex=" << ifindex;
  }

  auto id2ifi_it = id_to_ifindex.find(ifi2id_it->second);
  if (id2ifi_it == id_to_ifindex.end()) {
    auto pn_it = tap_devs.find(ifi2id_it->second);
    LOG(FATAL) << __FUNCTION__ << ": illegal removal of port "
               << pn_it->second->get_devname() << " with ifindex=" << ifindex;
  }

  ifindex_to_id.erase(ifi2id_it);
  port_deleted.erase(pd_it);
  id_to_ifindex.erase(id2ifi_it);
}

} // namespace basebox
<commit_msg>prevent possible double free<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <glog/logging.h>
#include "netlink/tap_manager.hpp"
#include "utils.hpp"

namespace basebox {

static inline void
release_packets(std::deque<std::pair<int, basebox::packet *>> &q) {
  for (auto i : q) {
    std::free(i.second);
  }
}

tap_io::~tap_io() { thread.stop(); }

void tap_io::register_tap(int fd, uint32_t port_id, switch_callback &cb) {
  {
    std::lock_guard<std::mutex> guard(events_mutex);
    events.emplace_back(std::make_tuple(TAP_IO_ADD, fd, port_id, &cb));
  }

  thread.wakeup();
}

void tap_io::unregister_tap(int fd, uint32_t port_id) {
  {
    std::lock_guard<std::mutex> guard(events_mutex);
    events.emplace_back(std::make_tuple(TAP_IO_REM, fd, port_id, nullptr));
  }

  thread.wakeup();
}

void tap_io::enqueue(int fd, basebox::packet *pkt) {
  if (fd == -1) {
    std::free(pkt);
    return;
  }

  {
    // store pkt in outgoing queue
    std::lock_guard<std::mutex> guard(pout_queue_mutex);
    pout_queue.emplace_back(std::make_pair(fd, pkt));
  }
  thread.wakeup();
}

void tap_io::handle_read_event(rofl::cthread &thread, int fd) {
  basebox::packet *pkt =
      (basebox::packet *)std::malloc(sizeof(basebox::packet));

  if (pkt == nullptr)
    return;

  pkt->len = read(fd, pkt->data, basebox::packet_data_len);

  if (pkt->len > 0) {
    VLOG(3) << __FUNCTION__ << ": read " << pkt->len << " bytes from fd=" << fd
            << " into pkt=" << pkt << " tid=" << pthread_self();
    std::pair<uint32_t, switch_callback *> &cb = sw_cbs.at(fd);
    cb.second->enqueue_to_switch(cb.first, pkt);
  } else {
    // error occured (or non-blocking)
    switch (errno) {
    case EAGAIN:
      LOG(ERROR) << __FUNCTION__
                 << ": EAGAIN XXX not implemented packet is dropped";
      std::free(pkt);
      break;
    default:
      LOG(ERROR) << __FUNCTION__ << ": unknown error occured";
      std::free(pkt);
      break;
    }
  }
}

void tap_io::handle_write_event(rofl::cthread &thread, int fd) {
  thread.drop_write_fd(fd);
  tx();
}

void tap_io::tx() {
  std::pair<int, basebox::packet *> pkt;
  std::deque<std::pair<int, basebox::packet *>> out_queue;

  {
    std::lock_guard<std::mutex> guard(pout_queue_mutex);
    std::swap(out_queue, pout_queue);
  }

  while (not out_queue.empty()) {

    pkt = out_queue.front();
    int rc = 0;
    if ((rc = write(pkt.first, pkt.second->data, pkt.second->len)) < 0) {
      switch (errno) {
      case EAGAIN:
        VLOG(1) << __FUNCTION__ << ": EAGAIN";
        {
          std::lock_guard<std::mutex> guard(pout_queue_mutex);
          std::move(out_queue.rbegin(), out_queue.rend(),
                    std::front_inserter(pout_queue));
        }
        thread.add_write_fd(pkt.first, true, false);
        return;
      case EIO:
        // tap not enabled drop packet
        VLOG(1) << __FUNCTION__ << ": EIO";
        release_packets(out_queue);
        return;
      default:
        // will drop packets
        release_packets(out_queue);
        LOG(ERROR) << __FUNCTION__ << ": unknown error occurred rc=" << rc
                   << " errno=" << errno << " '" << strerror(errno);
        return;
      }
    }
    std::free(pkt.second);
    out_queue.pop_front();
  }
}

void tap_io::handle_events() {
  std::lock_guard<std::mutex> guard(events_mutex);

  // register fds
  for (auto ev : events) {
    int fd = std::get<1>(ev);
    switch (std::get<0>(ev)) {

    case TAP_IO_ADD:
      sw_cbs.emplace(
          std::make_pair(fd, std::make_pair(std::get<2>(ev), std::get<3>(ev))));
      thread.add_read_fd(fd, true, false);
      break;
    case TAP_IO_REM:
      thread.drop_fd(fd, false);
      sw_cbs.erase(fd);
      break;
    default:
      break;
    }
  }
  events.clear();
}

tap_manager::~tap_manager() { destroy_tapdevs(); }

int tap_manager::create_tapdev(uint32_t port_id, const std::string &port_name,
                               switch_callback &cb) {
  int r = 0;
  bool dev_exists = false;
  bool dev_name_exists = false;
  auto dev_it = tap_devs.find(port_id);

  if (dev_it != tap_devs.end())
    dev_exists = true;

  {
    std::lock_guard<std::mutex> lock{rp_mutex};
    auto dev_name_it = tap_names.find(port_name);

    if (dev_name_it != tap_names.end())
      dev_name_exists = true;
  }

  if (!dev_exists && !dev_name_exists) {
    // create a new tap device

    ctapdev *dev;
    try {
      dev = new ctapdev(port_name);
      tap_devs.insert(std::make_pair(port_id, dev));
      {
        std::lock_guard<std::mutex> lock{rp_mutex};
        tap_names.insert(std::make_pair(port_name, port_id));
      }

      // create the port
      dev->tap_open();
      int fd = dev->get_fd();

      LOG(INFO) << __FUNCTION__ << ": port_id=" << port_id
                << " portname=" << port_name << " fd=" << fd << " ptr=" << dev;

      // start reading from port
      io.register_tap(fd, port_id, cb);

    } catch (std::exception &e) {
      LOG(ERROR) << __FUNCTION__ << ": failed to create tapdev " << port_name;
      r = -EINVAL;
    }
  } else {
    LOG(INFO) << __FUNCTION__ << ": " << port_name
              << " with port_id=" << port_id << " already existing";
  }
  return r;
}

int tap_manager::destroy_tapdev(uint32_t port_id,
                                const std::string &port_name) {
  auto it = tap_devs.find(port_id);
  if (it == tap_devs.end()) {
    LOG(WARNING) << __FUNCTION__ << ": called for invalid port_id=" << port_id
                 << " port_name=" << port_name;
    return 0;
  }

  // drop port from name mapping
  std::lock_guard<std::mutex> lock{rp_mutex};
  port_deleted.push_back(port_id);
  auto tap_names_it = tap_names.find(port_name);

  if (tap_names_it != tap_names.end()) {
    tap_names.erase(tap_names_it);
  }

  // drop port from port mapping
  auto dev = it->second;
  int fd = dev->get_fd();
  tap_devs.erase(it);
  delete dev;

  // XXX check if previous to delete
  io.unregister_tap(fd, port_id);

  return 0;
}

void tap_manager::destroy_tapdevs() {
  std::map<uint32_t, ctapdev *> ddevs;
  ddevs.swap(tap_devs);
  for (auto &dev : ddevs) {
    delete dev.second;
  }
  tap_names.clear();
}

int tap_manager::enqueue(uint32_t port_id, basebox::packet *pkt) {
  try {
    int fd = tap_devs.at(port_id)->get_fd();
    io.enqueue(fd, pkt);
  } catch (std::exception &e) {
    LOG(ERROR) << __FUNCTION__ << ": failed to enqueue packet " << pkt
               << " to port_id=" << port_id;
    std::free(pkt);
  }
  return 0;
}

void tap_manager::tap_dev_ready(int ifindex, const std::string &name) {
  auto it = ifindex_to_id.find(ifindex);
  if (it != ifindex_to_id.end())
    return;

  std::lock_guard<std::mutex> lock{rp_mutex};
  auto tn_it = tap_names.find(name);

  if (tn_it == tap_names.end()) {
    LOG(WARNING) << __FUNCTION__ << "invalid port name " << name;
    return;
  }

  // update maps
  auto id2ifi_it = id_to_ifindex.insert(std::make_pair(tn_it->second, ifindex));
  if (!id2ifi_it.second && id2ifi_it.first->second != ifindex) {
    // update only if the ifindex has changed
    LOG(WARNING) << __FUNCTION__
                 << ": enforced update of id:ifindex mapping id="
                 << id2ifi_it.first->first
                 << " ifindex(old) = " << id2ifi_it.first->second
                 << " ifindex(new)=" << ifindex;

    // remove overwritten index in ifindex_to_id map
    auto it = ifindex_to_id.find(id2ifi_it.first->second);
    if (it != ifindex_to_id.end()) {
      ifindex_to_id.erase(it);
    }

    // update the old one
    id2ifi_it.first->second = ifindex;
  }

  auto rv1 = ifindex_to_id.insert(std::make_pair(ifindex, tn_it->second));
  if (!rv1.second && rv1.first->second != tn_it->second) {
    // update only if the id has changed
    LOG(WARNING) << __FUNCTION__
                 << ": enforced update of ifindex:id mapping ifindex="
                 << ifindex << " id(old)=" << rv1.first->second
                 << " id(new)=" << tn_it->second;
    rv1.first->second = tn_it->second;
  }
}

void tap_manager::tap_dev_removed(int ifindex) {
  std::lock_guard<std::mutex> lock{rp_mutex};

  auto ifi2id_it = ifindex_to_id.find(ifindex);
  if (ifi2id_it == ifindex_to_id.end()) {
    VLOG(2) << __FUNCTION__
            << ": ignore removal of tap device with ifindex=" << ifindex;
    return;
  }

  // check if this port was scheduled for deletion
  auto pd_it =
      std::find(port_deleted.begin(), port_deleted.end(), ifi2id_it->second);
  if (pd_it == port_deleted.end()) {
    auto pn_it = tap_devs.find(ifi2id_it->second);
    LOG(FATAL) << __FUNCTION__ << ": illegal removal of port "
               << pn_it->second->get_devname() << " with ifindex=" << ifindex;
  }

  auto id2ifi_it = id_to_ifindex.find(ifi2id_it->second);
  if (id2ifi_it == id_to_ifindex.end()) {
    auto pn_it = tap_devs.find(ifi2id_it->second);
    LOG(FATAL) << __FUNCTION__ << ": illegal removal of port "
               << pn_it->second->get_devname() << " with ifindex=" << ifindex;
  }

  ifindex_to_id.erase(ifi2id_it);
  port_deleted.erase(pd_it);
  id_to_ifindex.erase(id2ifi_it);
}

} // namespace basebox
<|endoftext|>


<commit_before>// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <nvcore/Debug.h>
#include "CudaUtils.h"

#if defined HAVE_CUDA
#include <cuda_runtime.h>
#endif

using namespace nv;
using namespace cuda;

#if NV_OS_WIN32

#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>

static bool isWindowsVista()
{
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

	::GetVersionEx(&osvi);
	return osvi.dwMajorVersion >= 6;
}

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

static bool isWow32()
{
	LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");

    BOOL bIsWow64 = FALSE;

    if (NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
        {
			// Assume 32 bits.
            return true;
        }
    }

    return !bIsWow64;
}

#endif

/// Determine if CUDA is available.
bool nv::cuda::isHardwarePresent()
{
#if defined HAVE_CUDA
#if NV_OS_WIN32
	if (isWindowsVista()) return false;
	//if (isWindowsVista() || !isWow32()) return false;
#endif
	int count = deviceCount();
	if (count == 1)
	{
		// Make sure it's not an emulation device.
	    cudaDeviceProp deviceProp;
		cudaGetDeviceProperties(&deviceProp, 0);

		// deviceProp.name != Device Emulation (CPU)
		if (deviceProp.major == -1 || deviceProp.minor == -1)
		{
			return false;
		}

		// @@ Make sure that warp size == 32
	}

	return count > 0;
#else
	return false;
#endif
}

/// Get number of CUDA enabled devices.
int nv::cuda::deviceCount()
{
#if defined HAVE_CUDA
	int gpuCount = 0;

	cudaError_t result = cudaGetDeviceCount(&gpuCount);

	if (result == cudaSuccess)
	{
		return gpuCount;
	}
#endif
	return 0;
}

/// Activate the given devices.
bool nv::cuda::setDevice(int i)
{
	nvCheck(i < deviceCount());
#if defined HAVE_CUDA
	cudaError_t result = cudaSetDevice(i);
	return result == cudaSuccess;
#else
	return false;
#endif
}
<commit_msg>Fix end of lines<commit_after>// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include <nvcore/Debug.h>
#include "CudaUtils.h"

#if defined HAVE_CUDA
#include <cuda_runtime.h>
#endif

using namespace nv;
using namespace cuda;

#if NV_OS_WIN32

#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>

static bool isWindowsVista()
{
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

	::GetVersionEx(&osvi);
	return osvi.dwMajorVersion >= 6;
}

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

static bool isWow32()
{
	LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");

    BOOL bIsWow64 = FALSE;

    if (NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
        {
			// Assume 32 bits.
            return true;
        }
    }

    return !bIsWow64;
}

#endif

/// Determine if CUDA is available.
bool nv::cuda::isHardwarePresent()
{
#if defined HAVE_CUDA
#if NV_OS_WIN32
	if (isWindowsVista()) return false;
	//if (isWindowsVista() || !isWow32()) return false;
#endif
	int count = deviceCount();
	if (count == 1)
	{
		// Make sure it's not an emulation device.
	    cudaDeviceProp deviceProp;
		cudaGetDeviceProperties(&deviceProp, 0);

		// deviceProp.name != Device Emulation (CPU)
		if (deviceProp.major == -1 || deviceProp.minor == -1)
		{
			return false;
		}

		// @@ Make sure that warp size == 32
	}

	return count > 0;
#else
	return false;
#endif
}

/// Get number of CUDA enabled devices.
int nv::cuda::deviceCount()
{
#if defined HAVE_CUDA
	int gpuCount = 0;

	cudaError_t result = cudaGetDeviceCount(&gpuCount);

	if (result == cudaSuccess)
	{
		return gpuCount;
	}
#endif
	return 0;
}

/// Activate the given devices.
bool nv::cuda::setDevice(int i)
{
	nvCheck(i < deviceCount());
#if defined HAVE_CUDA
	cudaError_t result = cudaSetDevice(i);
	return result == cudaSuccess;
#else
	return false;
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010, 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <object/symbols.hh>
#include <urbi/object/event.hh>
#include <urbi/object/event-handler.hh>

namespace urbi
{
  namespace object
  {
    EventHandler::EventHandler(rEventHandler model)
      : source_(model->source_)
      , payload_(model->payload_)
      , detach_(false) // trigger has to be called before stop.
    {
      proto_add(model);
      slot_set(SYMBOL(active), to_urbi(true));
    }

    EventHandler::EventHandler(rEvent source, rList payload)
      : source_(source)
      , payload_(payload)
      , detach_(false) // trigger has to be called before stop.
    {
      proto_add(proto);
      slot_set(SYMBOL(active), to_urbi(true));
    }

    URBI_CXX_OBJECT_INIT(EventHandler)
    {
#define DECLARE(Name, Cxx)            \
      bind(SYMBOL_(Name), &EventHandler::Cxx)

      DECLARE(stop,    stop);
      DECLARE(source,  source);
      DECLARE(payload, payload);
#undef DECLARE
    }

    /*-------.
    | Stop.  |
    `-------*/

    // Use an intermediary bouncer to make sure the Executable is
    // stored in a smart pointer, and not deleted too early.
    static void
    executable_bouncer(rExecutable e, objects_type args)
    {
      (*e)(args);
    }

    void
    EventHandler::stop()
    {
      slot_update(SYMBOL(active), to_urbi(false));
      if (detach_)
      {
        runner::Runner& r = ::kernel::runner();
        sched::jobs_type children;
        // Copy container to avoid in-place modification problems.
        foreach (const stop_job_type& stop_job, stop_jobs_type(stop_jobs_))
        {
          typedef rObject(Executable::*fun_type)(objects_type);
          sched::rJob job = new runner::Interpreter
            (r.lobby_get(), r.scheduler_get(),
             boost::bind(&executable_bouncer,
                         stop_job.get<0>(), stop_job.get<1>()),
             this, SYMBOL(onleave));
          job->start_job();
        }
        r.yield_until_terminated(children);
      }
      else
        foreach (const stop_job_type& stop_job, stop_jobs_type(stop_jobs_))
          (*stop_job.get<0>())(stop_job.get<1>());

      stop_jobs_.clear();
      source()->active_.erase(this);
    }

    rList
    EventHandler::payload()
    {
      return payload_;
    }

    rEvent
    EventHandler::source()
    {
      return source_;
    }

    void
    EventHandler::trigger(bool detach)
    {
      detach_ = detach;
      source()->active_.insert(this);
      // Copy container to avoid in-place modification problems.
      foreach (callback_type* cb, callbacks_type(source()->callbacks_))
        (*cb)(payload_->value_get());
      // Copy container to avoid in-place modification problems.
      foreach (Event::rActions actions, listeners_type(source()->listeners_))
        trigger_job(actions, detach_);
    }

    void
    EventHandler::trigger_job(const rActions& actions, bool detach)
    {
      detach = detach && !actions->sync;
      runner::Runner& r = ::kernel::runner();
      if (actions->frozen)
        return;
      objects_type args;
      args << this << this << payload_;
      rObject pattern = nil_class;
      if (actions->guard)
        pattern = (*actions->guard)(args);
      if (pattern != void_class)
      {
        args << pattern;
        if (actions->leave)
          register_stop_job(stop_job_type(actions->leave, args, detach));
        if (actions->enter)
        {
          if (detach)
          {
            sched::rJob job = actions->enter.get()->make_job
              (actions->lobby ? actions->lobby : r.lobby_get(),
               r.scheduler_get(), args, SYMBOL(at));
            job->start_job();
          }
          else
            (*actions->enter)(args);
        }
      }
    }

    void
    EventHandler::register_stop_job(const stop_job_type& stop_job)
    {
      stop_jobs_ << stop_job;
    }
  }
}
<commit_msg>Prevent probable future bug.<commit_after>/*
 * Copyright (C) 2010, 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <object/symbols.hh>
#include <urbi/object/event.hh>
#include <urbi/object/event-handler.hh>

namespace urbi
{
  namespace object
  {
    EventHandler::EventHandler(rEventHandler model)
      : source_(model->source_)
      , payload_(model->payload_)
      , detach_(false) // trigger has to be called before stop.
    {
      proto_add(model);
      slot_set(SYMBOL(active), to_urbi(true));
    }

    EventHandler::EventHandler(rEvent source, rList payload)
      : source_(source)
      , payload_(payload)
      , detach_(false) // trigger has to be called before stop.
    {
      proto_add(proto);
      slot_set(SYMBOL(active), to_urbi(true));
    }

    URBI_CXX_OBJECT_INIT(EventHandler)
    {
#define DECLARE(Name, Cxx)            \
      bind(SYMBOL_(Name), &EventHandler::Cxx)

      DECLARE(stop,    stop);
      DECLARE(source,  source);
      DECLARE(payload, payload);
#undef DECLARE
    }

    /*-------.
    | Stop.  |
    `-------*/

    // Use an intermediary bouncer to make sure the Executable is
    // stored in a smart pointer, and not deleted too early.
    static void
    executable_bouncer(rExecutable e, objects_type args)
    {
      (*e)(args);
    }

    void
    EventHandler::stop()
    {
      slot_update(SYMBOL(active), to_urbi(false));
      if (detach_)
      {
        runner::Runner& r = ::kernel::runner();
        sched::jobs_type children;
        // Copy container to avoid in-place modification problems.
        foreach (const stop_job_type& stop_job, stop_jobs_type(stop_jobs_))
        {
          typedef rObject(Executable::*fun_type)(objects_type);
          sched::rJob job = new runner::Interpreter
            (r.lobby_get(), r.scheduler_get(),
             boost::bind(&executable_bouncer,
                         stop_job.get<0>(), stop_job.get<1>()),
             this, SYMBOL(onleave));
          job->start_job();
        }
        r.yield_until_terminated(children);
      }
      else
        foreach (const stop_job_type& stop_job, stop_jobs_type(stop_jobs_))
          (*stop_job.get<0>())(stop_job.get<1>());

      stop_jobs_.clear();
      source()->active_.erase(this);
    }

    rList
    EventHandler::payload()
    {
      return payload_;
    }

    rEvent
    EventHandler::source()
    {
      return source_;
    }

    void
    EventHandler::trigger(bool detach)
    {
      detach_ = detach;
      source()->active_.insert(this);
      // Copy the callback list in case it's modified.
      std::vector<callback_type> callbacks;
      callbacks.reserve(source()->callbacks_.size());
      foreach (callback_type* cb, source()->callbacks_)
        callbacks << *cb;
      // Trigger all callbacks.
      foreach (callback_type& cb, callbacks)
        cb(payload_->value_get());
      // Copy container to avoid in-place modification problems.
      foreach (Event::rActions actions, listeners_type(source()->listeners_))
        trigger_job(actions, detach_);
    }

    void
    EventHandler::trigger_job(const rActions& actions, bool detach)
    {
      detach = detach && !actions->sync;
      runner::Runner& r = ::kernel::runner();
      if (actions->frozen)
        return;
      objects_type args;
      args << this << this << payload_;
      rObject pattern = nil_class;
      if (actions->guard)
        pattern = (*actions->guard)(args);
      if (pattern != void_class)
      {
        args << pattern;
        if (actions->leave)
          register_stop_job(stop_job_type(actions->leave, args, detach));
        if (actions->enter)
        {
          if (detach)
          {
            sched::rJob job = actions->enter.get()->make_job
              (actions->lobby ? actions->lobby : r.lobby_get(),
               r.scheduler_get(), args, SYMBOL(at));
            job->start_job();
          }
          else
            (*actions->enter)(args);
        }
      }
    }

    void
    EventHandler::register_stop_job(const stop_job_type& stop_job)
    {
      stop_jobs_ << stop_job;
    }
  }
}
<|endoftext|>


<commit_before>/*
 * ShaderTest.cxx
 *
 * Author
 *     Andrew Brown <adb1413@rit.edu>
 */
#include "config.h"
#include <cassert>
#include <stdexcept>
#include "glycerin/shader/Shader.hpp"
#include <GL/glfw.h>
using namespace std;
using namespace Glycerin;

/**
 * Unit test for Shader.
 */
class ShaderTest {
public:

    /**
     * Ensures a bad fragment shader does not compile correctly.
     */
    void testCompileWithBadFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    gl_Position = vec4(1);\n"
                "}\n");
        shader.compile();
        if (shader.compiled()) {
            throw runtime_error("Compiled bad fragment shader!");
        }
    }

    /**
     * Ensures a good fragment shader compiles correctly.
     */
    void testCompileWithGoodFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    FragColor = vec4(1);\n"
                "}\n");
        shader.compile();
        if (!shader.compiled()) {
            throw runtime_error("Could not compile good fragment shader!");
        }
    }

    /**
     * Ensures a bad vertex shader does not compile correctly.
     */
    void testCompileWithBadVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_FragColor = MCVertex;\n"
                "}\n");
        shader.compile();
        if (shader.compiled()) {
            throw runtime_error("Compiled bad vertex shader!");
        }
    }

    /**
     * Ensures a good vertex shader compiles correctly.
     */
    void testCompileWithGoodVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_Position = MCVertex;\n"
                "}\n");
        shader.compile();
        if (!shader.compiled()) {
            throw runtime_error("Could not compile good vertex shader!");
        }
    }

    /**
     * Ensures making a new fragment shader works.
     */
    void testCreateWithFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        if (glGetError() != 0) {
            throw runtime_error("Could not create fragment shader!");
        }
        shader.dispose();
    }

    /**
     * Ensures making a new geometry shader works.
     */
    void testCreateWithGeometryShader() {
        Shader shader = Shader::create(GL_GEOMETRY_SHADER);
        if (glGetError() != 0) {
            throw runtime_error("Could not create geometry shader!");
        }
        shader.dispose();
    }

    /**
     * Ensures making a new vertex shader works.
     */
    void testCreateWithVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        if (glGetError() != 0) {
            throw runtime_error("Could not create vertex shader!");
        }
        shader.dispose();
    }

    /**
     * Ensures handle returns a valid handle with a fragment shader.
     */
    void testHandleWithFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        assert (shader.handle() > 0);
    }

    /**
     * Ensures handle returns a valid handle with a geometry shader.
     */
    void testHandleWithGeometryShader() {
        Shader shader = Shader::create(GL_GEOMETRY_SHADER);
        assert (shader.handle() > 0);
    }

    /**
     * Ensures handle returns a valid handle with a vertex shader.
     */
    void testHandleWithVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        assert (shader.handle() > 0);
    }

    /**
     * Ensures compiling a bad fragment shader generates a log.
     */
    void testLogWithBadFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    gl_Position = vec4(1);\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (!log.empty());
    }

    /**
     * Ensures compiling a good fragment shader generates an empty log.
     */
    void testLogWithGoodFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    FragColor = vec4(1);\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (log.empty());
    }

    /**
     * Ensures compiling a bad vertex shader generates a log.
     */
    void testLogWithBadVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    FragColor = MCVertex;\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (!log.empty());
    }

    /**
     * Ensures compiling a good vertex shader generates an empty log.
     */
    void testLogWithGoodVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_Position = MCVertex;\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (log.empty());
    }

    /**
     * Ensures equality operator returns true for shaders with the same handle.
     */
    void testOperatorEqualEqualWithEqual() {
        Shader s1 = Shader::create(GL_VERTEX_SHADER);
        Shader s2 = Shader::wrap(s1.handle());
        assert (s1 == s2);
    }

    /**
     * Ensures inequality operator returns true for shaders with different handles.
     */
    void testOperatorNotEqualWithUnequal() {
        Shader s1 = Shader::create(GL_VERTEX_SHADER);
        Shader s2 = Shader::create(GL_VERTEX_SHADER);
        assert (s1 != s2);
    }

    /**
     * Ensures both forms of source works correctly.
     */
    void testSource() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        string source =
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_Position = MCVertex;\n"
                "}\n";
        shader.source(source);
        assert (shader.source() == source);
    }

    /**
     * Ensures a fragment shader's type is GL_FRAGMENT_SHADER.
     */
    void testTypeWithFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        assert(shader.type() == GL_FRAGMENT_SHADER);
    }

    /**
     * Ensures a geometry shader's type is GL_GEOMETRY_SHADER.
     */
    void testTypeWithGeometryShader() {
        Shader shader = Shader::create(GL_GEOMETRY_SHADER);
        assert(shader.type() == GL_GEOMETRY_SHADER);
    }

    /**
     * Ensures a vertex shader's type is GL_VERTEX_SHADER.
     */
    void testTypeWithVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        assert(shader.type() == GL_VERTEX_SHADER);
    }

    /**
     * Ensures wrapping an existing shader works correctly.
     */
    void testWrapWithGoodHandle() {
        const GLuint handle = glCreateShader(GL_FRAGMENT_SHADER);
        Shader shader = Shader::wrap(handle);
        assert (shader.handle() == handle);
    }

    /**
     * Ensures wrapping a non-existent shader throws an exception.
     */
    void testWrapWithBadHandle() {
        const GLuint handle = -1;
        try {
            Shader shader = Shader::wrap(handle);
        } catch (std::invalid_argument &e) {
            // Exception caught
            return;
        }
        throw runtime_error("Exception not caught!");
    }
};

int main(int argc, char* argv[]) {

    // Initialize
    if (!glfwInit()) {
        cerr << "Could not initialize GLFW!" << endl;
        return 1;
    }

    // Open a window
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
    glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwOpenWindow(512, 512, 0, 0, 0, 0, 0, 0, GLFW_WINDOW);

    // Run the test
    ShaderTest test;
    try {
        test.testCompileWithBadFragmentShader();
        test.testCompileWithGoodFragmentShader();
        test.testCompileWithBadVertexShader();
        test.testCompileWithGoodVertexShader();
        test.testCreateWithFragmentShader();
        test.testCreateWithGeometryShader();
        test.testCreateWithVertexShader();
        test.testHandleWithFragmentShader();
        test.testHandleWithGeometryShader();
        test.testHandleWithVertexShader();
        test.testLogWithBadFragmentShader();
        test.testLogWithGoodFragmentShader();
        test.testLogWithBadVertexShader();
        test.testLogWithGoodVertexShader();
        test.testOperatorEqualEqualWithEqual();
        test.testOperatorNotEqualWithUnequal();
        test.testSource();
        test.testTypeWithFragmentShader();
        test.testTypeWithGeometryShader();
        test.testTypeWithVertexShader();
        test.testWrapWithGoodHandle();
        test.testWrapWithBadHandle();
    } catch (exception& e) {
        cerr << e.what() << endl;
        throw;
    }

    // Exit
    glfwTerminate();
    return 0;
}
<commit_msg>Fixed bad fragment shaders possibly compiling in ShaderTest<commit_after>/*
 * ShaderTest.cxx
 *
 * Author
 *     Andrew Brown <adb1413@rit.edu>
 */
#include "config.h"
#include <cassert>
#include <stdexcept>
#include "glycerin/shader/Shader.hpp"
#include <GL/glfw.h>
using namespace std;
using namespace Glycerin;

/**
 * Unit test for Shader.
 */
class ShaderTest {
public:

    /**
     * Ensures a bad fragment shader does not compile correctly.
     */
    void testCompileWithBadFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    FragColor = vec4(1)\n"
                "}\n");
        shader.compile();
        if (shader.compiled()) {
            throw runtime_error("Compiled bad fragment shader!");
        }
    }

    /**
     * Ensures a good fragment shader compiles correctly.
     */
    void testCompileWithGoodFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    FragColor = vec4(1);\n"
                "}\n");
        shader.compile();
        if (!shader.compiled()) {
            throw runtime_error("Could not compile good fragment shader!");
        }
    }

    /**
     * Ensures a bad vertex shader does not compile correctly.
     */
    void testCompileWithBadVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_FragColor = MCVertex;\n"
                "}\n");
        shader.compile();
        if (shader.compiled()) {
            throw runtime_error("Compiled bad vertex shader!");
        }
    }

    /**
     * Ensures a good vertex shader compiles correctly.
     */
    void testCompileWithGoodVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_Position = MCVertex;\n"
                "}\n");
        shader.compile();
        if (!shader.compiled()) {
            throw runtime_error("Could not compile good vertex shader!");
        }
    }

    /**
     * Ensures making a new fragment shader works.
     */
    void testCreateWithFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        if (glGetError() != 0) {
            throw runtime_error("Could not create fragment shader!");
        }
        shader.dispose();
    }

    /**
     * Ensures making a new geometry shader works.
     */
    void testCreateWithGeometryShader() {
        Shader shader = Shader::create(GL_GEOMETRY_SHADER);
        if (glGetError() != 0) {
            throw runtime_error("Could not create geometry shader!");
        }
        shader.dispose();
    }

    /**
     * Ensures making a new vertex shader works.
     */
    void testCreateWithVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        if (glGetError() != 0) {
            throw runtime_error("Could not create vertex shader!");
        }
        shader.dispose();
    }

    /**
     * Ensures handle returns a valid handle with a fragment shader.
     */
    void testHandleWithFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        assert (shader.handle() > 0);
    }

    /**
     * Ensures handle returns a valid handle with a geometry shader.
     */
    void testHandleWithGeometryShader() {
        Shader shader = Shader::create(GL_GEOMETRY_SHADER);
        assert (shader.handle() > 0);
    }

    /**
     * Ensures handle returns a valid handle with a vertex shader.
     */
    void testHandleWithVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        assert (shader.handle() > 0);
    }

    /**
     * Ensures compiling a bad fragment shader generates a log.
     */
    void testLogWithBadFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    FragColor = vec4(1)\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (!log.empty());
    }

    /**
     * Ensures compiling a good fragment shader generates an empty log.
     */
    void testLogWithGoodFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 FragColor;\n"
                "void main() {\n"
                "    FragColor = vec4(1);\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (log.empty());
    }

    /**
     * Ensures compiling a bad vertex shader generates a log.
     */
    void testLogWithBadVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    FragColor = MCVertex;\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (!log.empty());
    }

    /**
     * Ensures compiling a good vertex shader generates an empty log.
     */
    void testLogWithGoodVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        shader.source(
                "#version 140\n"
                "out vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_Position = MCVertex;\n"
                "}\n");
        shader.compile();
        const string log = shader.log();
        assert (log.empty());
    }

    /**
     * Ensures equality operator returns true for shaders with the same handle.
     */
    void testOperatorEqualEqualWithEqual() {
        Shader s1 = Shader::create(GL_VERTEX_SHADER);
        Shader s2 = Shader::wrap(s1.handle());
        assert (s1 == s2);
    }

    /**
     * Ensures inequality operator returns true for shaders with different handles.
     */
    void testOperatorNotEqualWithUnequal() {
        Shader s1 = Shader::create(GL_VERTEX_SHADER);
        Shader s2 = Shader::create(GL_VERTEX_SHADER);
        assert (s1 != s2);
    }

    /**
     * Ensures both forms of source works correctly.
     */
    void testSource() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        string source =
                "#version 140\n"
                "in vec4 MCVertex;\n"
                "void main() {\n"
                "    gl_Position = MCVertex;\n"
                "}\n";
        shader.source(source);
        assert (shader.source() == source);
    }

    /**
     * Ensures a fragment shader's type is GL_FRAGMENT_SHADER.
     */
    void testTypeWithFragmentShader() {
        Shader shader = Shader::create(GL_FRAGMENT_SHADER);
        assert(shader.type() == GL_FRAGMENT_SHADER);
    }

    /**
     * Ensures a geometry shader's type is GL_GEOMETRY_SHADER.
     */
    void testTypeWithGeometryShader() {
        Shader shader = Shader::create(GL_GEOMETRY_SHADER);
        assert(shader.type() == GL_GEOMETRY_SHADER);
    }

    /**
     * Ensures a vertex shader's type is GL_VERTEX_SHADER.
     */
    void testTypeWithVertexShader() {
        Shader shader = Shader::create(GL_VERTEX_SHADER);
        assert(shader.type() == GL_VERTEX_SHADER);
    }

    /**
     * Ensures wrapping an existing shader works correctly.
     */
    void testWrapWithGoodHandle() {
        const GLuint handle = glCreateShader(GL_FRAGMENT_SHADER);
        Shader shader = Shader::wrap(handle);
        assert (shader.handle() == handle);
    }

    /**
     * Ensures wrapping a non-existent shader throws an exception.
     */
    void testWrapWithBadHandle() {
        const GLuint handle = -1;
        try {
            Shader shader = Shader::wrap(handle);
        } catch (std::invalid_argument &e) {
            // Exception caught
            return;
        }
        throw runtime_error("Exception not caught!");
    }
};

int main(int argc, char* argv[]) {

    // Initialize
    if (!glfwInit()) {
        cerr << "Could not initialize GLFW!" << endl;
        return 1;
    }

    // Open a window
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
    glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwOpenWindow(512, 512, 0, 0, 0, 0, 0, 0, GLFW_WINDOW);

    // Run the test
    ShaderTest test;
    try {
        test.testCompileWithBadFragmentShader();
        test.testCompileWithGoodFragmentShader();
        test.testCompileWithBadVertexShader();
        test.testCompileWithGoodVertexShader();
        test.testCreateWithFragmentShader();
        test.testCreateWithGeometryShader();
        test.testCreateWithVertexShader();
        test.testHandleWithFragmentShader();
        test.testHandleWithGeometryShader();
        test.testHandleWithVertexShader();
        test.testLogWithBadFragmentShader();
        test.testLogWithGoodFragmentShader();
        test.testLogWithBadVertexShader();
        test.testLogWithGoodVertexShader();
        test.testOperatorEqualEqualWithEqual();
        test.testOperatorNotEqualWithUnequal();
        test.testSource();
        test.testTypeWithFragmentShader();
        test.testTypeWithGeometryShader();
        test.testTypeWithVertexShader();
        test.testWrapWithGoodHandle();
        test.testWrapWithBadHandle();
    } catch (exception& e) {
        cerr << e.what() << endl;
        throw;
    }

    // Exit
    glfwTerminate();
    return 0;
}
<|endoftext|>


<commit_before>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
#include <v8.h>
#include <string.h>

#include "AndroidUtil.h"
#include "TitaniumModule.h"
#include "Assets.h"
#include "EventEmitter.h"
#include "JNIUtil.h"
#include "KrollJavaScript.h"
#include "KrollProxy.h"
#include "ScriptsModule.h"
#include "TypeConverter.h"
#include "V8Util.h"

#include "org.appcelerator.kroll.KrollModule.h"
#include "ti.modules.titanium.BufferProxy.h"
#include "ti.modules.titanium.utils.UtilsModule.h"
#include "org.appcelerator.titanium.TiBlob.h"
#include "V8Runtime.h"

#define TAG "V8Runtime"

namespace titanium {

Persistent<Context> V8Runtime::globalContext;

/* static */
void V8Runtime::collectWeakRef(Persistent<Value> ref, void *parameter)
{
	jobject v8Object = (jobject) parameter;
	ref.Dispose();
	JNIUtil::getJNIEnv()->DeleteGlobalRef(v8Object);
}

/* static */
jobject V8Runtime::newObject(Handle<Object> object)
{
	HandleScope scope;

	JNIEnv *env = JNIUtil::getJNIEnv();
	if (!env) return NULL;

	jlong ptr = (jlong) *Persistent<Object>::New(object);
	jobject v8Object = env->NewGlobalRef(env->NewObject(JNIUtil::v8ObjectClass, JNIUtil::v8ObjectInitMethod, ptr));

	// make a 2nd persistent weakref so we can be informed of GC
	Persistent<Object> weakRef = Persistent<Object>::New(object);
	weakRef.MakeWeak(reinterpret_cast<void*>(v8Object), V8Runtime::collectWeakRef);

	return v8Object;
}

/* static */
void V8Runtime::setKrollProxyV8Object(jobject krollProxy, jobject v8Object)
{
	JNIEnv *env = JNIUtil::getJNIEnv();
	if (!env) {
		// TODO error message
		return;
	}

	env->CallVoidMethod(krollProxy, JNIUtil::krollProxySetV8ObjectMethod, v8Object);
	if (env->ExceptionCheck()) {
		env->ExceptionDescribe();
		env->ExceptionClear();
	}
}

static Handle<Value> binding(const Arguments& args)
{
	static Persistent<Object> binding_cache;

	HandleScope scope;
	Local<String> module = args[0]->ToString();
	String::Utf8Value module_v(module);
	if (binding_cache.IsEmpty()) {
		binding_cache = Persistent<Object>::New(Object::New());
	}

	Local<Object> exports;
	if (binding_cache->Has(module)) {
		exports = binding_cache->Get(module)->ToObject();
	} else if (strcmp(*module_v, "natives") == 0) {
		exports = Object::New();
		KrollJavaScript::DefineNatives(exports);
		binding_cache->Set(module, exports);
	} else if (strcmp(*module_v, "evals") == 0) {
		exports = Object::New();
		ScriptsModule::Initialize(exports);
		binding_cache->Set(module, exports);
	} else if (strcmp(*module_v, "titanium") == 0) {
		exports = Object::New();
		TitaniumModule::Initialize(exports);
		binding_cache->Set(module, exports);
	} else {
		return ThrowException(Exception::Error(String::New("No such module")));
	}
	return scope.Close(exports);
}

/* static */
void V8Runtime::bootstrap(Local<Object> global)
{
	EventEmitter::Initialize();

	DEFINE_METHOD(global, "binding", binding);
	global->Set(String::NewSymbol("EventEmitter"), EventEmitter::constructorTemplate->GetFunction());

	TryCatch tryCatch;
	Handle<Value> result = ExecuteString(KrollJavaScript::MainSource(), IMMUTABLE_STRING_LITERAL("kroll.js"));

	if (tryCatch.HasCaught()) {
		ReportException(tryCatch, true);
		JNIUtil::terminateVM();
	}
	if (!result->IsFunction()) {
		LOGF(TAG, "kroll.js result is not a function");
		ReportException(tryCatch, true);
		JNIUtil::terminateVM();
	}

	Handle<Function> mainFunction = Handle<Function>::Cast(result);
	Local<Value> args[] = { global };
	mainFunction->Call(global, 1, args);

	if (tryCatch.HasCaught()) {
		ReportException(tryCatch, true);
		LOGE(TAG, "has caught!!");
		JNIUtil::terminateVM();
	}
}

static jobject jruntime;

} // namespace titanium

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     org_appcelerator_kroll_runtime_v8_V8Runtime
 * Method:    nativeInit
 * Signature: (Lorg/appcelerator/kroll/runtime/v8/V8Runtime;)J
 */
JNIEXPORT jlong JNICALL Java_org_appcelerator_kroll_runtime_v8_V8Runtime_nativeInit(JNIEnv *env, jclass clazz,
	jobject self)
{
	titanium::JNIScope jniScope(env);
	HandleScope scope;

	LOGD(TAG, "V8Runtime_nativeInit");
	titanium::jruntime = env->NewGlobalRef(self);
	titanium::JNIUtil::initCache();

	Persistent<Context> context = Persistent<Context>::New(Context::New());
	context->Enter();

	Local<Object> global = context->Global();
	titanium::V8Runtime::bootstrap(global);

	titanium::initKrollProxy(global, env);
	titanium::V8Runtime::globalContext = context;

	titanium::KrollModule::Initialize(global, env);
	titanium::BufferProxy::Initialize(global, env);
	titanium::UtilsModule::Initialize(global, env);
	titanium::TiBlob::Initialize(global, env);

	Persistent<Object> wrappedContext(titanium::ScriptsModule::WrapContext(context));
	return (jlong) *wrappedContext;
}

/*
 * Class:     org_appcelerator_kroll_runtime_v8_V8Runtime
 * Method:    nativeDispose
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_appcelerator_kroll_runtime_v8_V8Runtime_nativeDispose(JNIEnv *env, jclass clazz)
{
	titanium::V8Runtime::globalContext->Exit();

	titanium::V8Runtime::globalContext.Dispose();
	V8::Dispose();

	env->DeleteGlobalRef(titanium::jruntime);
	titanium::jruntime = NULL;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
	titanium::JNIUtil::javaVm = vm;
	return JNI_VERSION_1_4;
}

#ifdef __cplusplus
}
#endif
<commit_msg>move modules initialization code into bootstrap method<commit_after>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
#include <v8.h>
#include <string.h>

#include "AndroidUtil.h"
#include "TitaniumModule.h"
#include "Assets.h"
#include "EventEmitter.h"
#include "JNIUtil.h"
#include "KrollJavaScript.h"
#include "KrollProxy.h"
#include "ScriptsModule.h"
#include "TypeConverter.h"
#include "V8Util.h"

#include "org.appcelerator.kroll.KrollModule.h"
#include "ti.modules.titanium.BufferProxy.h"
#include "ti.modules.titanium.utils.UtilsModule.h"
#include "org.appcelerator.titanium.TiBlob.h"
#include "V8Runtime.h"

#define TAG "V8Runtime"

namespace titanium {

Persistent<Context> V8Runtime::globalContext;

/* static */
void V8Runtime::collectWeakRef(Persistent<Value> ref, void *parameter)
{
	jobject v8Object = (jobject) parameter;
	ref.Dispose();
	JNIUtil::getJNIEnv()->DeleteGlobalRef(v8Object);
}

/* static */
jobject V8Runtime::newObject(Handle<Object> object)
{
	HandleScope scope;

	JNIEnv *env = JNIUtil::getJNIEnv();
	if (!env) return NULL;

	jlong ptr = (jlong) *Persistent<Object>::New(object);
	jobject v8Object = env->NewGlobalRef(env->NewObject(JNIUtil::v8ObjectClass, JNIUtil::v8ObjectInitMethod, ptr));

	// make a 2nd persistent weakref so we can be informed of GC
	Persistent<Object> weakRef = Persistent<Object>::New(object);
	weakRef.MakeWeak(reinterpret_cast<void*>(v8Object), V8Runtime::collectWeakRef);

	return v8Object;
}

/* static */
void V8Runtime::setKrollProxyV8Object(jobject krollProxy, jobject v8Object)
{
	JNIEnv *env = JNIUtil::getJNIEnv();
	if (!env) {
		// TODO error message
		return;
	}

	env->CallVoidMethod(krollProxy, JNIUtil::krollProxySetV8ObjectMethod, v8Object);
	if (env->ExceptionCheck()) {
		env->ExceptionDescribe();
		env->ExceptionClear();
	}
}

static Handle<Value> binding(const Arguments& args)
{
	static Persistent<Object> binding_cache;

	HandleScope scope;
	Local<String> module = args[0]->ToString();
	String::Utf8Value module_v(module);
	if (binding_cache.IsEmpty()) {
		binding_cache = Persistent<Object>::New(Object::New());
	}

	Local<Object> exports;
	if (binding_cache->Has(module)) {
		exports = binding_cache->Get(module)->ToObject();
	} else if (strcmp(*module_v, "natives") == 0) {
		exports = Object::New();
		KrollJavaScript::DefineNatives(exports);
		binding_cache->Set(module, exports);
	} else if (strcmp(*module_v, "evals") == 0) {
		exports = Object::New();
		ScriptsModule::Initialize(exports);
		binding_cache->Set(module, exports);
	} else if (strcmp(*module_v, "titanium") == 0) {
		exports = Object::New();
		TitaniumModule::Initialize(exports);
		binding_cache->Set(module, exports);
	} else {
		return ThrowException(Exception::Error(String::New("No such module")));
	}
	return scope.Close(exports);
}

/* static */
void V8Runtime::bootstrap(Local<Object> global)
{
	EventEmitter::Initialize();

	DEFINE_METHOD(global, "binding", binding);
	global->Set(String::NewSymbol("EventEmitter"), EventEmitter::constructorTemplate->GetFunction());

	TryCatch tryCatch;
	Handle<Value> result = ExecuteString(KrollJavaScript::MainSource(), IMMUTABLE_STRING_LITERAL("kroll.js"));

	if (tryCatch.HasCaught()) {
		ReportException(tryCatch, true);
		JNIUtil::terminateVM();
	}
	if (!result->IsFunction()) {
		LOGF(TAG, "kroll.js result is not a function");
		ReportException(tryCatch, true);
		JNIUtil::terminateVM();
	}

	Handle<Function> mainFunction = Handle<Function>::Cast(result);
	Local<Value> args[] = { global };
	mainFunction->Call(global, 1, args);

	if (tryCatch.HasCaught()) {
		ReportException(tryCatch, true);
		LOGE(TAG, "has caught!!");
		JNIUtil::terminateVM();
	}

	titanium::initKrollProxy(global, titanium::JNIScope::getEnv());

	titanium::KrollModule::Initialize(global, titanium::JNIScope::getEnv());
	titanium::BufferProxy::Initialize(global, titanium::JNIScope::getEnv());
	titanium::UtilsModule::Initialize(global, titanium::JNIScope::getEnv());
	titanium::TiBlob::Initialize(global, titanium::JNIScope::getEnv());
}

static jobject jruntime;

} // namespace titanium

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     org_appcelerator_kroll_runtime_v8_V8Runtime
 * Method:    nativeInit
 * Signature: (Lorg/appcelerator/kroll/runtime/v8/V8Runtime;)J
 */
JNIEXPORT jlong JNICALL Java_org_appcelerator_kroll_runtime_v8_V8Runtime_nativeInit(JNIEnv *env, jclass clazz,
	jobject self)
{
	titanium::JNIScope jniScope(env);
	HandleScope scope;

	LOGD(TAG, "V8Runtime_nativeInit");
	titanium::jruntime = env->NewGlobalRef(self);
	titanium::JNIUtil::initCache();

	Persistent<Context> context = Persistent<Context>::New(Context::New());
	context->Enter();
	titanium::V8Runtime::globalContext = context;

	Local<Object> global = context->Global();
	titanium::V8Runtime::bootstrap(global);

	Persistent<Object> wrappedContext(titanium::ScriptsModule::WrapContext(context));
	return (jlong) *wrappedContext;
}

/*
 * Class:     org_appcelerator_kroll_runtime_v8_V8Runtime
 * Method:    nativeDispose
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_appcelerator_kroll_runtime_v8_V8Runtime_nativeDispose(JNIEnv *env, jclass clazz)
{
	titanium::V8Runtime::globalContext->Exit();

	titanium::V8Runtime::globalContext.Dispose();
	V8::Dispose();

	env->DeleteGlobalRef(titanium::jruntime);
	titanium::jruntime = NULL;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
	titanium::JNIUtil::javaVm = vm;
	return JNI_VERSION_1_4;
}

#ifdef __cplusplus
}
#endif
<|endoftext|>