/** Set keepalive state * * @param active true to start keepalive, false to end keepalive */ static void cka_state_set(bool active) { static bool keepalive_is_active = false; static bool flagged = false; static tick_t started = 0; if( keepalive_is_active != active ) { tick_t now = cka_tick_get_current(); if( (keepalive_is_active = active) ) { #ifdef ENABLE_WAKELOCKS wakelock_lock(cpu_wakelock, -1); #endif started = now; mce_log(LL_DEVEL, "keepalive started"); } else { tick_t dur = now - started; if( dur > KEEPALIVE_STATE_WARN_LIMIT_MS ) { mce_log(LL_CRIT, "long keepalive stopped after %"PRId64" ms", dur); } else { mce_log(LL_DEVEL, "keepalive stopped after %"PRId64" ms", dur); } flagged = false; #ifdef ENABLE_WAKELOCKS wakelock_unlock(cpu_wakelock); #endif } } else if( keepalive_is_active && !flagged ) { tick_t now = cka_tick_get_current(); tick_t dur = now - started; if( dur > KEEPALIVE_STATE_WARN_LIMIT_MS ) { flagged = true; mce_log(LL_CRIT, "long keepalive active after %"PRId64" ms", dur); } } }
static int android_wakelock_acquire(struct wakelock *lock) { if (lock == NULL) return -EINVAL; if (lock->acquisitions > 0) { lock->acquisitions++; return 0; } if (wakelock_lock(lock->name) < 0) return -EIO; lock->acquisitions++; return 0; }
/** Evaluate need for suspend blocking */ static void mia_keepalive_rethink(void) { static bool have_lock = false; bool need_lock = (mia_keepalive_id != 0); if( have_lock == need_lock ) goto EXIT; mce_log(LL_DEBUG, "inactivity notify wakelock: %s", need_lock ? "OBTAIN" : "RELEASE"); if( (have_lock = need_lock) ) wakelock_lock("mce_inactivity_notify", -1); else wakelock_unlock("mce_inactivity_notify"); EXIT: return; }
/** Re-evaluate the end of cpu-keepalive period * * Calculates maximum of wakeup period and per client renew periods * and uses it to reprogram the end of cpu-keepalive period */ static void cpu_keepalive_rethink(void) { time_t maxtime = wakeup_timeout; GHashTableIter iter; gpointer key, val; #ifdef ENABLE_WAKELOCKS wakelock_lock(cpu_wakelock, -1); #endif g_hash_table_iter_init(&iter, clients); while( g_hash_table_iter_next (&iter, &key, &val) ) { client_t *client = val; if( maxtime < client->timeout ) { maxtime = client->timeout; } } cpu_keepalive_set_timer(maxtime); }
/** * Callback for successful chunk I/O * * @param source The source of the activity * @param condition The I/O condition * @param data The iomon structure * @return Depending on error policy this function either exits * or returns TRUE */ static gboolean io_chunk_cb(GIOChannel *source, GIOCondition condition, gpointer data) { iomon_struct *iomon = data; gchar *buffer = NULL; gsize bytes_want = 4096; gsize bytes_read = 0; gsize chunks_read = 0; gsize chunks_done = 0; GIOStatus io_status; GError *error = NULL; gboolean status = TRUE; /* Silence warnings */ (void)condition; if (iomon == NULL) { mce_log(LL_CRIT, "iomon == NULL!"); status = FALSE; goto EXIT; } iomon->latest_io_condition = 0; /* Seek to the beginning of the file before reading if needed */ if (iomon->rewind == TRUE) { g_io_channel_seek_position(source, 0, G_SEEK_SET, &error); if( error ) { mce_log(LL_ERR, "%s: seek error: %s", iomon->file, error->message); } /* Reset errno, * to avoid false positives down the line */ errno = 0; g_clear_error(&error); } if( iomon->chunk_size < bytes_want ) { bytes_want -= bytes_want % iomon->chunk_size; } else { bytes_want = iomon->chunk_size; } buffer = g_malloc(bytes_want); #ifdef ENABLE_WAKELOCKS /* Since the locks on kernel side are released once all * events are read, we must obtain the userspace lock * before reading the available data */ wakelock_lock("mce_input_handler", -1); #endif io_status = g_io_channel_read_chars(source, buffer, bytes_want, &bytes_read, &error); /* If the read was interrupted, ignore */ if (io_status == G_IO_STATUS_AGAIN) { g_clear_error(&error); } if( bytes_read % iomon->chunk_size ) { mce_log(LL_WARN, "Incomplete chunks read from: %s", iomon->file); } /* Process the data, and optionally ignore some of it */ if( (chunks_read = bytes_read / iomon->chunk_size) ) { gchar *chunk = buffer; for( ; chunks_done < chunks_read ; chunk += iomon->chunk_size ) { ++chunks_done; if (iomon->callback(chunk, iomon->chunk_size) != TRUE) { continue; } /* if possible, seek to the end of file */ if (iomon->seekable) { g_io_channel_seek_position(iomon->iochan, 0, G_SEEK_END, &error); } /* in any case ignore rest of the data already read */ break; } } mce_log(LL_INFO, "%s: status=%s, data=%d/%d=%d+%d, skipped=%d", iomon->file, io_status_name(io_status), bytes_read, (int)iomon->chunk_size, chunks_read, bytes_read % (int)iomon->chunk_size, chunks_read - chunks_done); #ifdef ENABLE_WAKELOCKS /* Release the lock after we're done with processing it */ wakelock_unlock("mce_input_handler"); #endif g_free(buffer); /* Were there any errors? */ if (error != NULL) { mce_log(LL_ERR, "Error when reading from %s: %s", iomon->file, error->message); if ((error->code == G_IO_CHANNEL_ERROR_FAILED) && (errno == ENODEV) && (iomon->seekable)) { errno = 0; g_clear_error(&error); g_io_channel_seek_position(iomon->iochan, 0, G_SEEK_END, &error); if( error ) { mce_log(LL_ERR, "%s: seek error: %s", iomon->file, error->message); } } else { status = FALSE; } /* Reset errno, * to avoid false positives down the line */ errno = 0; g_clear_error(&error); } else if ((bytes_read == 0) && (io_status != G_IO_STATUS_EOF) && (io_status != G_IO_STATUS_AGAIN)) { mce_log(LL_ERR, "Empty read from %s", iomon->file); } EXIT: if ((status == FALSE) && (iomon != NULL) && (iomon->error_policy == MCE_IO_ERROR_POLICY_EXIT)) { // FIXME: this is not how one should exit from mainloop mce_quit_mainloop(); exit(EXIT_FAILURE); } return TRUE; }