/* * This method is used to inject a custom BPS event into the BPS event handler using * the channel and domain that we saved during the initialisation process. */ void NfcWorker::interruptBpsWaitLoop(unsigned int code) { int rc = 0; if (!_timeToDie) { qDebug() << "XXXX Trying to interrupt..."; _interruptMutex.lock(); bps_event_t *interruptEvent; rc = 0; qDebug() << "XXXX Time(ms) : " << getSysTimeMs() << ": bps_event_create() - entering"; rc = bps_event_create(&interruptEvent, _bpsInterruptDomain, code, 0, 0); qDebug() << "XXXX Time(ms) : " << getSysTimeMs() << ": bps_event_create() - exited"; if (rc) { qDebug() << "XXXX Unable to create a BPS custom event"; } else { qDebug() << "XXXX Created a BPS custom event"; } rc = 0; qDebug() << "XXXX Time(ms) : " << getSysTimeMs() << ": bps_channel_push_event() - entering"; rc = bps_channel_push_event(_bpsChannel, interruptEvent); qDebug() << "XXXX Time(ms) : " << getSysTimeMs() << ": bps_channel_push_event() - exited"; if (rc) { qDebug() << "XXXX Unable to push custom event onto BPS channel"; } else { qDebug() << "XXXX Pushed custom event onto BPS channel"; } _interruptMutex.unlock(); } else { qDebug() << "XXXX No need to interrupt NfcWorker since already closing down"; } }
void BBMBPS::StartContactEvents() { if (!contactEventsEnabled) { bps_event_t *event = NULL; bps_event_create(&event, m_BBMInternalDomain, INTERNAL_EVENT_CONTACT_EVENTS, NULL, NULL); bps_channel_push_event(m_eventChannel, event); } }
void BBMBPS::Register(const std::string& uuid) { bps_event_t *event = NULL; bps_event_payload_t payload; char *stringBuf = new char[uuid.size()]; payload.data1 = reinterpret_cast<uintptr_t>(stringBuf); bps_event_create(&event, m_BBMInternalDomain, INTERNAL_EVENT_REGISTER, &payload, NULL); bps_channel_push_event(m_eventChannel, event); }
void QEventDispatcherBlackberry::wakeUp() { Q_D(QEventDispatcherBlackberry); if (d->wakeUps.testAndSetAcquire(0, 1)) { bps_event_t *event; if (Q_LIKELY(bps_event_create(&event, bpsUnblockDomain, 0, 0, 0) == BPS_SUCCESS)) { if (Q_LIKELY(bps_channel_push_event(d->bps_channel, event) == BPS_SUCCESS)) return; else bps_event_destroy(event); } qWarning("QEventDispatcherBlackberry: wakeUp failed"); } }
static void status_callback(camera_handle_t handle, camera_devstatus_t status, uint16_t extra, void* arg) { fprintf(stderr, "status notification: %d, %d\n", status, extra); // when all photo-taking callbacks have completed, the capture-complete event is emitted if (status == CAMERA_STATUS_CAPTURECOMPLETE) { // picture-taking is done, so wake up the main thread again via bps. // note that we are using the void* arg here as the bps channel to deliver // the event on. this is just to demonstrate data passing between // camera_take_photo() and the various callback functions. bps_event_t* photo_done_event; bps_event_create(&photo_done_event, photo_done_domain, 0, NULL, NULL); bps_channel_push_event((int)arg, photo_done_event); } }
/** * The main entry point. */ int main(int argc, char *argv[]) { pthread_t accel_thread; bool exit_application = false; int rc; /* * Before we can listen for events from the BlackBerry Tablet OS platform * services, we need to initialize the BPS infrastructure */ bps_initialize(); /* * Initialize the screen so that the window group Id is properly set, * to allow the dialogs to be displayed. */ if (setup_screen() != EXIT_SUCCESS) { fprintf(stderr, "Unable to initialize screen."); exit(-1); } /* * Once the BPS infrastructure has been initialized we can register for * events from the various BlackBerry Tablet OS platform services. The * Navigator service manages and delivers application life cycle and * visibility events. * * We register a custom event domain so that we can communicate with the * the accelerometer thread. We will need to tell it to quit once we get * the NAVIGATOR_EXIT. * * We request Navigator events so that we can track when the system is * terminating the application (NAVIGATOR_EXIT event). * */ local_event_domain = bps_register_domain(); if (local_event_domain == -1) { fprintf(stderr, "Error registering custom event domain: %s", strerror(errno)); exit(-1); } if (BPS_SUCCESS != navigator_request_events(0)) { fprintf(stderr, "Error requesting navigator events: %s", strerror(errno)); exit(-1); } if (BPS_SUCCESS != dialog_request_events(0)) { fprintf(stderr, "Error requesting dialog events: %s", strerror(errno)); exit(-1); } if (BPS_SUCCESS != geolocation_request_events(0)) { fprintf(stderr, "Error requesting geolocation events: %s", strerror(errno)); exit(-1); } geolocation_set_period(1); /* * Create and display the dialogs that will show the data. */ create_top_dialog(); show_top_dialog_message("Geolocation getting first fix"); /* * Before initializing the accelerometer service we must ensure the device * supports it. */ if (!sensor_is_supported(SENSOR_TYPE_ACCELEROMETER)) { /** * If the device does not support accelerometer then notify the user, * clean up and exit */ snprintf(msg, MSG_SIZE, "Accelerometer not supported by device!"); show_top_dialog_message(msg); /* * Destroy the dialog, if it exists and cleanup screen resources. */ destroy_top_dialog(); cleanup_screen(); bps_shutdown(); return EXIT_FAILURE; } /* * Create the accelerometer event thread. */ rc = pthread_create(&accel_thread, NULL, accel_main, NULL); if (rc != 0) { fprintf(stderr, "Error in pthread_create: %s", strerror(errno)); exit(-1); } while (!exit_application) { /* * Using a negative timeout (-1) in the call to bps_get_event(...) * ensures that we don't busy wait by blocking until an event is * available. */ bps_event_t *event = NULL; bps_get_event(&event, -1); if (event) { if (bps_event_get_domain(event) == geolocation_get_domain()) { handle_geolocation_response(event); } else if (bps_event_get_domain(event) == navigator_get_domain()) { exit_application = handle_navigator_event(event); } } } geolocation_stop_events(0); /* * Avoid a possible race condition where accel_chid has not yet * been assigned a valid channel ID. */ pthread_mutex_lock(&chidMutex); while (accel_chid == -1) { pthread_cond_wait(&chidCond, &chidMutex); } pthread_mutex_unlock(&chidMutex); bps_event_t *stop_request_event = NULL; if (BPS_SUCCESS != bps_event_create(&stop_request_event, local_event_domain, STOP_REQUEST, NULL, NULL)) { fprintf(stderr, "Unable to create event: %s", strerror(errno)); exit(-1); } if (BPS_SUCCESS != bps_channel_push_event(accel_chid, stop_request_event)) { fprintf(stderr, "Unable to push event: %s", strerror(errno)); } pthread_join(accel_thread, NULL); /* * Destroy the dialog, if it exists. */ destroy_top_dialog(); bps_shutdown(); cleanup_screen(); return 0; }
int QEventDispatcherBlackberry::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timespec *timeout) { Q_UNUSED(nfds); Q_D(QEventDispatcherBlackberry); const BBScopedLoopLevelCounter bbLoopCounter(d); BpsChannelScopeSwitcher channelSwitcher(d->bps_channel); // prepare file sets for bps callback d->ioData->count = 0; d->ioData->readfds = readfds; d->ioData->writefds = writefds; d->ioData->exceptfds = exceptfds; // reset all file sets if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); if (exceptfds) FD_ZERO(exceptfds); bps_event_t *event = 0; unsigned int eventCount = 0; // If an event handler called through filterEvent() starts a nested event loop by creating a // new QEventLoop, we will recursively enter this function again. However, each time // bps_get_event() is called, it destroys the last event it handed out before returning the // next event. We don't want it to destroy the event that triggered the nested event loop, // since there may still be more handlers that need to get that event, once the nested event // loop is done and control returns to the outer event loop. // // So we move an event to a holding channel, which takes ownership of the event. Putting // the event on our own channel allows us to manage when it is destroyed, keeping it alive // until we know we are done with it. Each recursive call of this function needs to have // it's own holding channel, since a channel is a queue, not a stack. // // However, a recursive call into this function happens very rarely compared to the many // times this function is called. We don't want to create a holding channel for each time // this function is called, only when it is called recursively. Thus we have the instance // variable d->holding_channel to use in the common case. We keep track of recursive calls // with d->loop_level. If we are in a recursive call, then we create a new holding channel // for this run. int holding_channel = d->holding_channel; if ((d->loop_level > 1) && Q_UNLIKELY(bps_channel_create(&holding_channel, 0) != BPS_SUCCESS)) { qWarning("QEventDispatcherBlackberry: bps_channel_create failed"); holding_channel = -1; } // Convert timeout to milliseconds int timeoutTotal = -1; if (timeout) timeoutTotal = timespecToMillisecs(*timeout); int timeoutLeft = timeoutTotal; timespec startTime = qt_gettime(); // This loop exists such that we can drain the bps event queue of all native events // more efficiently than if we were to return control to Qt after each event. This // is important for handling touch events which can come in rapidly. forever { // Only emit the awake() and aboutToBlock() signals in the second iteration. For the // first iteration, the UNIX event dispatcher will have taken care of that already. // Also native events are actually processed one loop iteration after they were // retrieved with bps_get_event(). // Filtering the native event should happen between the awake() and aboutToBlock() // signal emissions. The calls awake() - filterNativeEvent() - aboutToBlock() - // bps_get_event() need not to be interrupted by a break or return statement. if (eventCount > 0) { if (event) { emit awake(); filterNativeEvent(QByteArrayLiteral("bps_event_t"), static_cast<void*>(event), 0); emit aboutToBlock(); if (Q_LIKELY(holding_channel != -1)) { // We are now done with this BPS event. Destroy it. destroyHeldBpsEvent(holding_channel); } } // Update the timeout // Clock source is monotonic, so we can recalculate how much timeout is left if (timeoutTotal != -1) { timespec t2 = qt_gettime(); timeoutLeft = timeoutTotal - (timespecToMillisecs(t2) - timespecToMillisecs(startTime)); if (timeoutLeft < 0) timeoutLeft = 0; } timespec tnext; if (d->timerList.timerWait(tnext)) { int timeoutNext = timespecToMillisecs(tnext); if (timeoutNext < timeoutLeft || timeoutTotal == -1) { timeoutTotal = timeoutLeft = timeoutNext; startTime = qt_gettime(); } } } event = 0; { // We need to increase loop level in this scope, // because bps_get_event can also invoke callbacks QScopedLoopLevelCounter loopLevelCounter(d->threadData); // Wait for event or file to be ready const int result = bps_get_event(&event, timeoutLeft); if (Q_UNLIKELY(result != BPS_SUCCESS)) qWarning("QEventDispatcherBlackberry: bps_get_event failed"); } if (!event) // In case of !event, we break out of the loop to let Qt process the timers break; // (since timeout has expired) and socket notifiers that are now ready. if (bps_event_get_domain(event) == bpsUnblockDomain) { timeoutTotal = 0; // in order to immediately drain the event queue of native events event = 0; // (especially touch move events) we don't break out here } else { // Move the event to our holding channel so we can manage when it is destroyed. if (Q_LIKELY(holding_channel != 1) && Q_UNLIKELY(bps_channel_push_event(holding_channel, event) != BPS_SUCCESS)) { qWarning("QEventDispatcherBlackberry: bps_channel_push_event failed"); } } ++eventCount; // Make sure we are not trapped in this loop due to continuous native events // also we cannot recalculate the timeout without a monotonic clock as the time may have changed const unsigned int maximumEventCount = 12; if (Q_UNLIKELY((eventCount > maximumEventCount && timeoutLeft == 0) || !QElapsedTimer::isMonotonic())) { if (event) { filterNativeEvent(QByteArrayLiteral("bps_event_t"), static_cast<void*>(event), 0); if (Q_LIKELY(holding_channel != -1)) { // We are now done with this BPS event. Destroy it. destroyHeldBpsEvent(holding_channel); } } break; } } // If this was a recursive call into this function, a new holding channel was created for // this run, so destroy it now. if ((holding_channel != d->holding_channel) && Q_LIKELY(holding_channel != -1) && Q_UNLIKELY(bps_channel_destroy(holding_channel) != BPS_SUCCESS)) { qWarning("QEventDispatcherBlackberry: bps_channel_destroy failed"); } // the number of bits set in the file sets return d->ioData->count; }
void BBMBPS::SendEndEvent() { bps_event_t *event = NULL; bps_event_create(&event, m_BBMInternalDomain, INTERNAL_EVENT_STOP, NULL, NULL); bps_channel_push_event(m_eventChannel, event); }