int main(int argc, char** argv) { cbuf *cb1 = cbuf_alloc(); // make sure the cbuf grows and shrinks appropriately int capacity = cbuf_capacity(cb1); check(capacity > 0, "Initial capacity > 0"); check(cbuf_size(cb1) == 0, "Initial size == 0"); for(int i = 0; i < capacity; i++) { cbuf_update(cb1, 60, 1.291); } check(cbuf_size(cb1) == cbuf_capacity(cb1), "Size is allowed to grow to capacity"); cbuf_update(cb1, 60, 1.291); // inserting one more than what the original structure could contain int new_capacity = cbuf_capacity(cb1); check(new_capacity > capacity, "Capacity grows when necessary"); // inserting an update that's > 5 minutes older than all of the data // in the structure cbuf_update(cb1, 60 + 6 * 60, 1.291); check(cbuf_capacity(cb1) < new_capacity, "Capacity shrinks when able"); check(cbuf_size(cb1) == 1, "Aged out records are removed correctly"); cbuf_free(cb1); return 0; }
/** * Blocking read from a cbuf * * This function is compatible to the glip_read_b() function and can be used in * backend implementations using a cbuf for storing incoming data. * * @param[in] buf the buffer to read from * @param[in] size how much data is supposed to be read * @param[out] data the read data * @param[out] size_read how much data has been read * @param[in] timeout the maximum duration the read operation can take * * @return 0 if reading was successful * @return -ETIMEDOUT if the read timeout was hit * @return -ECANCELED if the blocking operation was cancelled * @return any other value indicates failure * * @see glip_read_b() */ int gb_util_cbuf_read_b(struct cbuf *buf, size_t size, uint8_t *data, size_t *size_read, unsigned int timeout) { int rv; int retval = 0; struct timespec ts; *size_read = 0; if (size > cbuf_size(buf)) { /* * This is not a problem for non-blocking reads, but blocking reads will * block forever in this case as the maximum amount of data ever * available is limited by the buffer size. * @todo: This can be solved by loop-reading until timeout */ return -1; } /* * Wait until sufficient data is available to be read. */ if (timeout != 0) { clock_gettime(CLOCK_REALTIME, &ts); timespec_add_ns(&ts, timeout * 1000 * 1000); } size_t level = cbuf_fill_level(buf); while (level < size) { if (timeout == 0) { rv = cbuf_wait_for_level_change(buf, level); } else { rv = cbuf_timedwait_for_level_change(buf, level, &ts); } retval = rv; if (rv == -ETIMEDOUT) { goto read_ret; } else if (rv != 0) { goto ret; } level = cbuf_fill_level(buf); } /* * We read whatever data is available, and assume a timeout if the available * amount of data does not match the requested amount. */ read_ret: rv = gb_util_cbuf_read(buf, size, data, size_read); if (rv == 0 && size != *size_read) { retval = -ETIMEDOUT; } ret: return retval; }
/** * Send a status message back to the user who issued the !history command. */ static int command_status(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd, struct cbuffer* buf) { struct cbuffer* msg = cbuf_create(cbuf_size(buf) + strlen(cmd->prefix) + 8); cbuf_append_format(msg, "*** %s: %s", cmd->prefix, cbuf_get(buf)); plugin->hub.send_message(plugin, user, cbuf_get(msg)); cbuf_destroy(msg); cbuf_destroy(buf); return 0; }
static cio_err_t on_client_write(cio_handle_t* h, cio_dispatcher_t* d, void* p) { int count; DEBUG_ENTER(); count = send(h->fd, h->buf_out.data, cbuf_size(&h->buf_out), 0); if (count <= 0) return CIO_ERR_CLOSE; cbuf_pop_front(&h->buf_out, count); return CIO_ERR_SUCCESS; }
int sys_read_console(char* buffer, int size) { if (!list_empty(&keyboardqueue) || keyboard_serving_read) block_current_task(&keyboardqueue, BLOCK_AT_END); keyboard_serving_read = 1; // 1) If we can satisfy the read(), copy the needed bytes and return // 2) If we can't and the buffer is full, copy the entire input buffer and block // 3) Otherwise, block int* remaining_bytes = &keyboard_req_bytes[task_struct_to_task_index(current())]; *remaining_bytes = size; for (;;) { // Copy bytes from the keyboard buffer to the user buffer int read_bytes = 0; if (cbuf_size(&keyboard_input) >= *remaining_bytes) read_bytes = cbuf_read(&keyboard_input, buffer, *remaining_bytes, copy_to_user); else if (cbuf_full(&keyboard_input)) read_bytes = cbuf_read(&keyboard_input, buffer, cbuf_size(&keyboard_input), copy_to_user); buffer += read_bytes; *remaining_bytes -= read_bytes; if (*remaining_bytes == 0) break; // Block process back at the beginning of the keyboard queue keyboard_serving_read = 0; block_current_task(&keyboardqueue, BLOCK_AT_BEGINNING); } keyboard_serving_read = 0; return size - *remaining_bytes; }
void keyboard_key_pressed(char c) { // If the buffer is full and there are no tasks waiting to read from it, discard it if (list_empty(&keyboardqueue) && cbuf_full(&keyboard_input)) return; cbuf_insert(&keyboard_input, c); // Unblock first task in the keyboard queue if needed if (list_empty(&keyboardqueue)) // TODO Should we discard keypresses if there are no blocked tasks? return; if (keyboard_serving_read) // Avoid unblocking two or more tasks from the keyboard queue return; if (cbuf_full(&keyboard_input) || cbuf_size(&keyboard_input) >= get_pending_keyboard_bytes()) { keyboard_serving_read = 1; unblock_task(&keyboardqueue); } }