/** Callback from Java thread after alarm from AlarmService fires. */
static void bt_alarm_cb(void *data)
{
    GKI_disable();

    alarm_service.timer_last_expired_us = GKI_now_us();

    UINT32 ticks_taken = 0;
    UINT32 ticks_scheduled = alarm_service.ticks_scheduled;

    if (alarm_service.timer_last_expired_us > alarm_service.timer_started_us)
    {
        ticks_taken = GKI_MS_TO_TICKS((alarm_service.timer_last_expired_us
                                       - alarm_service.timer_started_us) / 1000);
    } else {
        // this could happen on some platform
        ALOGE("%s now_us %lld less than %lld", __func__, alarm_service.timer_last_expired_us,
              alarm_service.timer_started_us);
    }
    GKI_enable();

    GKI_timer_update(ticks_taken > ticks_scheduled
                   ? ticks_taken : ticks_scheduled);
}
Пример #2
0
void timer_thread(signed long id)
{
    GKI_TRACE_1("%s enter", __func__);
    struct timespec delay;
    int timeout = 1000;  /* 10  ms per system tick  */
    int err;

    while(!shutdown_timer)
    {
        delay.tv_sec = timeout / 1000;
        delay.tv_nsec = 1000 * 1000 * (timeout%1000);

        /* [u]sleep can't be used because it uses SIGALRM */

        do
        {
            err = nanosleep(&delay, &delay);
        } while (err < 0 && errno ==EINTR);

        GKI_timer_update(1);
    }
    GKI_TRACE_1("%s exit", __func__);
    pthread_exit(NULL);
}
void GKI_run (void *p_task_id)
{
    struct timespec delay;
    int err;
    volatile int * p_run_cond = &gki_cb.os.no_timer_suspend;

#ifndef GKI_NO_TICK_STOP
    /* adjust btld scheduling scheme now */
    gki_set_timer_scheduling();

    /* register start stop function which disable timer loop in GKI_run() when no timers are
     * in any GKI/BTA/BTU this should save power when BTLD is idle! */
    GKI_timer_queue_register_callback( gki_system_tick_start_stop_cback );
    GKI_TRACE( "GKI_run(): Start/Stop GKI_timer_update_registered!" );
#endif

#ifdef NO_GKI_RUN_RETURN
    pthread_attr_t timer_attr;

    shutdown_timer = 0;

    pthread_attr_init(&timer_attr);
    if (pthread_create( &timer_thread_id,
              &timer_attr,
              timer_thread,
              NULL) != 0 )
    {
        GKI_ERROR_LOG("pthread_create failed to create timer_thread!\n\r");
        return;
    }

#else
    GKI_TRACE("GKI_run ");
    for (;;)
    {
        do
        {
            /* adjust hear bit tick in btld by changning TICKS_PER_SEC!!!!! this formula works only for
             * 1-1000ms heart beat units! */
            delay.tv_sec = LINUX_SEC / 1000;
            delay.tv_nsec = 1000 * 1000 * (LINUX_SEC % 1000);

            /* [u]sleep can't be used because it uses SIGALRM */
            do
            {
                err = nanosleep(&delay, &delay);
            } while (err < 0 && errno == EINTR);

            /* the unit should be alsways 1 (1 tick). only if you vary for some reason heart beat tick
             * e.g. power saving you may want to provide more ticks
             */
            GKI_timer_update( 1 );
            /* BT_TRACE_2( TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, "update: tv_sec: %d, tv_nsec: %d", delay.tv_sec, delay.tv_nsec ); */
        } while ( GKI_TIMER_TICK_RUN_COND == *p_run_cond );

        /* currently on reason to exit above loop is no_timer_suspend == GKI_TIMER_TICK_STOP_COND
         * block timer main thread till re-armed by  */

        GKI_TIMER_TRACE(">>> SUSPENDED GKI_timer_update()" );

        pthread_mutex_lock( &gki_cb.os.gki_timer_mutex );
        pthread_cond_wait( &gki_cb.os.gki_timer_cond, &gki_cb.os.gki_timer_mutex );
        pthread_mutex_unlock( &gki_cb.os.gki_timer_mutex );

        /* potentially we need to adjust os gki_cb.com.OSTicks */
        GKI_TIMER_TRACE(">>> RESTARTED GKI_timer_update(): run_cond: %d",
                    *p_run_cond );

    }
#endif
    return;
}
void* timer_thread(void *arg)
{
    int timeout_ns=0;
    struct timespec timeout;
    struct timespec previous = {0,0};
    struct timespec current;
    int err;
    int delta_ns;
    int restart;
    tGKI_OS         *p_os = &gki_cb.os;
    int  *p_run_cond = &p_os->no_timer_suspend;

    /* Indicate that tick is just starting */
    restart = 1;

    prctl(PR_SET_NAME, (unsigned long)"gki timer", 0, 0, 0);

    raise_priority_a2dp(TASK_HIGH_GKI_TIMER);

    while(!shutdown_timer)
    {
        /* If the timer has been stopped (no SW timer running) */
        if (*p_run_cond == GKI_TIMER_TICK_STOP_COND)
        {
            /*
             * We will lock/wait on GKI_timer_mutex.
             * This mutex will be unlocked when timer is re-started
             */
            GKI_TRACE("GKI_run lock mutex");
            pthread_mutex_lock(&p_os->gki_timer_mutex);

            /* We are here because the mutex has been released by timer cback */
            /* Let's release it for future use */
            GKI_TRACE("GKI_run unlock mutex");
            pthread_mutex_unlock(&p_os->gki_timer_mutex);

            /* Indicate that tick is just starting */
            restart = 1;
        }

        /* Get time */
        clock_gettime(CLOCK_MONOTONIC, &current);

        /* Check if tick was just restarted, indicating to the compiler that this is
         * unlikely to happen (to help branch prediction) */
        if (__unlikely(restart))
        {
            /* Clear the restart indication */
            restart = 0;

            timeout_ns = (GKI_TICKS_TO_MS(1) * 1000000);
        }
        else
        {
            /* Compute time elapsed since last sleep start */
            delta_ns = current.tv_nsec - previous.tv_nsec;
            delta_ns += (current.tv_sec - previous.tv_sec) * 1000000000;

            /* Compute next timeout:
             *    timeout = (next theoretical expiration) - current time
             *    timeout = (previous time + timeout + delay) - current time
             *    timeout = timeout + delay - (current time - previous time)
             *    timeout += delay - delta */
            timeout_ns += (GKI_TICKS_TO_MS(1) * 1000000) - delta_ns;
        }
        /* Save the current time for next iteration */
        previous = current;

        timeout.tv_sec = 0;

        /* Sleep until next theoretical tick time.  In case of excessive
           elapsed time since last theoretical tick expiration, it is
           possible that the timeout value is negative.  To protect
           against this error, we set minimum sleep time to 10% of the
           tick period.  We indicate to compiler that this is unlikely to
           happen (to help branch prediction) */

        if (__unlikely(timeout_ns < ((GKI_TICKS_TO_MS(1) * 1000000) * 0.1)))
        {
            timeout.tv_nsec = (GKI_TICKS_TO_MS(1) * 1000000) * 0.1;

            /* Print error message if tick really got delayed
               (more than 5 ticks) */
            if (timeout_ns < GKI_TICKS_TO_MS(-5) * 1000000)
            {
                GKI_ERROR_LOG("tick delayed > 5 slots (%d,%d) -- cpu overload ? ",
                        timeout_ns, GKI_TICKS_TO_MS(-5) * 1000000);
            }
        }
        else
        {
            timeout.tv_nsec = timeout_ns;
        }

        do
        {
            /* [u]sleep can't be used because it uses SIGALRM */
            err = nanosleep(&timeout, &timeout);
        } while (err < 0 && errno == EINTR);

        /* Increment the GKI time value by one tick and update internal timers */
        GKI_timer_update(1);
    }
    GKI_TRACE("gki_ulinux: Exiting timer_thread");
    pthread_exit(NULL);
    return NULL;
}