int cf_queue_delete(cf_queue *q, void *buf, bool only_one) { if (NULL == q) return(CF_QUEUE_ERR); QUEUE_LOCK(q); bool found = false; if (CF_Q_SZ(q)) { for (uint32_t i = q->read_offset ; i < q->write_offset ; i++) { int rv = memcmp(CF_Q_ELEM_PTR(q,i), buf, q->elementsz); if (rv == 0) { // delete! cf_queue_delete_offset(q, i); found = true; if (only_one == true) goto Done; } }; } Done: QUEUE_UNLOCK(q); if (found == false) return(CF_QUEUE_EMPTY); else return(CF_QUEUE_OK); }
// // This assumes the element we're looking for is unique! Returns // CF_QUEUE_NOMATCH if the element is not found or not moved. // int cf_queue_priority_change(cf_queue_priority *priority_q, const void *ptr, int new_pri) { cf_queue_priority_lock(priority_q); cf_queue *queues[3]; queues[0] = priority_q->high_q; queues[1] = priority_q->medium_q; queues[2] = priority_q->low_q; int dest_q_itr = CF_QUEUE_PRIORITY_HIGH - new_pri; cf_queue *q; for (int q_itr = 0; q_itr < 3; q_itr++) { q = queues[q_itr]; if (q_itr == dest_q_itr || CF_Q_SZ(q) == 0) { continue; } for (uint32_t i = q->read_offset; i < q->write_offset; i++) { if (memcmp(CF_Q_ELEM_PTR(q, i), ptr, q->element_sz) == 0) { // Move it to the queue with desired priority. cf_queue_delete_offset(q, i); cf_queue_push(queues[dest_q_itr], ptr); cf_queue_priority_unlock(priority_q); return CF_QUEUE_OK; } } } cf_queue_priority_unlock(priority_q); return CF_QUEUE_NOMATCH; }
// // Reduce the inner queues whose priorities are different to 'new_pri'. If the // callback returns -1, move that element to the inner queue whose priority is // 'new_pri' and return CF_QUEUE_OK. Returns CF_QUEUE_NOMATCH if callback never // triggers a move. // int cf_queue_priority_reduce_change(cf_queue_priority *priority_q, int new_pri, cf_queue_reduce_fn cb, void *udata) { cf_queue_priority_lock(priority_q); cf_queue *queues[3]; queues[0] = priority_q->high_q; queues[1] = priority_q->medium_q; queues[2] = priority_q->low_q; int dest_q_itr = CF_QUEUE_PRIORITY_HIGH - new_pri; cf_queue *q; for (int q_itr = 0; q_itr < 3; q_itr++) { q = queues[q_itr]; if (q_itr == dest_q_itr || CF_Q_SZ(q) == 0) { continue; } for (uint32_t i = q->read_offset; i < q->write_offset; i++) { int rv = cb(CF_Q_ELEM_PTR(q, i), udata); if (rv == 0) { continue; } if (rv == -1) { // Found it - move to desired queue and return. uint8_t* buf = alloca(q->element_sz); memcpy(buf, CF_Q_ELEM_PTR(q, i), q->element_sz); cf_queue_delete_offset(q, i); cf_queue_push(queues[dest_q_itr], buf); cf_queue_priority_unlock(priority_q); return CF_QUEUE_OK; } } } cf_queue_priority_unlock(priority_q); return CF_QUEUE_NOMATCH; }
int cf_queue_reduce(cf_queue *q, cf_queue_reduce_fn cb, void *udata) { if (NULL == q) return(-1); /* FIXME error checking */ if (q->threadsafe && (0 != pthread_mutex_lock(&q->LOCK))) return(-1); if (CF_Q_SZ(q)) { // it would be faster to have a local variable to hold the index, // and do it in bytes or something, but a delete // will change the read and write offset, so this is simpler for now // can optimize if necessary later.... for (uint i = q->read_offset ; i < q->write_offset ; i++) { int rv = cb(CF_Q_ELEM_PTR(q, i), udata); // rv == 0 i snormal case, just increment to next point if (rv == -1) { break; // found what it was looking for } else if (rv == -2) { // delete! cf_queue_delete_offset(q, i); goto Found; } }; } Found: if (q->threadsafe && (0 != pthread_mutex_unlock(&q->LOCK))) { fprintf(stderr, "unlock failed\n"); return(-1); } return(0); }
/** * Use this function to find an element to pop from the queue using a reduce * callback function. Have the callback function return -1 when you want to pop * the element and stop reducing. If you have not popped an element, * CF_QUEUE_NOMATCH is returned. */ int cf_queue_priority_reduce_pop(cf_queue_priority *priority_q, void *buf, cf_queue_reduce_fn cb, void *udata) { cf_queue_priority_lock(priority_q); cf_queue *queues[3]; queues[0] = priority_q->high_q; queues[1] = priority_q->medium_q; queues[2] = priority_q->low_q; cf_queue *q; for (int q_itr = 0; q_itr < 3; q_itr++) { q = queues[q_itr]; if (CF_Q_SZ(q) == 0) { continue; } for (uint32_t i = q->read_offset; i < q->write_offset; i++) { int rv = cb(CF_Q_ELEM_PTR(q, i), udata); if (rv == 0) { continue; } if (rv == -1) { // Found an element, so copy to 'buf', delete from q, and return. memcpy(buf, CF_Q_ELEM_PTR(q, i), q->element_sz); cf_queue_delete_offset(q, i); cf_queue_priority_unlock(priority_q); return CF_QUEUE_OK; } } } cf_queue_priority_unlock(priority_q); return CF_QUEUE_NOMATCH; }
int cf_queue_delete(cf_queue *q, void *buf, bool only_one) { if (NULL == q) return(CF_QUEUE_ERR); /* FIXME error checking */ if (q->threadsafe && (0 != pthread_mutex_lock(&q->LOCK))) return(CF_QUEUE_ERR); bool found = false; if (CF_Q_SZ(q)) { for (uint i = q->read_offset ; i < q->write_offset ; i++) { int rv = memcmp(CF_Q_ELEM_PTR(q,i), buf, q->elementsz); if (rv == 0) { // delete! cf_queue_delete_offset(q, i); found = true; if (only_one == true) goto Done; } }; } Done: if (q->threadsafe && (0 != pthread_mutex_unlock(&q->LOCK))) { fprintf(stderr, "unlock failed\n"); return(-1); } if (found == false) return(CF_QUEUE_EMPTY); else return(CF_QUEUE_OK); }
int cf_queue_reduce(cf_queue *q, cf_queue_reduce_fn cb, void *udata) { if (NULL == q) return(-1); QUEUE_LOCK(q); if (CF_Q_SZ(q)) { // it would be faster to have a local variable to hold the index, // and do it in uint8_ts or something, but a delete // will change the read and write offset, so this is simpler for now // can optimize if necessary later.... for (uint32_t i = q->read_offset ; i < q->write_offset ; i++) { int rv = cb(CF_Q_ELEM_PTR(q, i), udata); // rv == 0 i snormal case, just increment to next point if (rv == -1) { break; // found what it was looking for } else if (rv == -2) { // delete! cf_queue_delete_offset(q, i); goto Found; } }; } Found: QUEUE_UNLOCK(q); return(0); }
/** * Use this function to find an element to pop from the queue using a reduce * callback function. Have the callback function * return -1 when you know you want to pop the element immediately, returns -2 * when the element is the best candidate for popping found so far but you want * to keep looking, and returns 0 when you are not interested in popping * the element. You then pop the best candidate you've found - either the * "-1 case" or the last "-2 case". If you have not found a suitable candidate, * CF_QUEUE_NOMATCH is returned. */ int cf_queue_priority_reduce_pop(cf_queue_priority *priority_q, void *buf, cf_queue_reduce_fn cb, void *udata) { if (NULL == priority_q) return(-1); if (priority_q->threadsafe && (0 != pthread_mutex_lock(&priority_q->LOCK))) return(-1); int rv = 0; cf_queue *queues[3]; queues[0] = priority_q->high_q; queues[1] = priority_q->medium_q; queues[2] = priority_q->low_q; cf_queue *q; int found_index = -1; for (int q_itr = 0; q_itr < 3; q_itr++) { q = queues[q_itr]; if (CF_Q_SZ(q)) { // it would be faster to have a local variable to hold the index, // and do it in bytes or something, but a delete // will change the read and write offset, so this is simpler for now // can optimize if necessary later.... for (uint i = q->read_offset ; i < q->write_offset ; i++) { rv = cb(CF_Q_ELEM_PTR(q, i), udata); // rv == 0 is normal case, just increment to next point if (rv == -1) { found_index = i; break; // found what it was looking for, so break } else if (rv == -2) { // found new candidate, but keep looking for one better found_index = i; } }; break; // only traverse the highest priority q } } if (found_index >= 0) { // found an element, so memcpy to buf, delete from q, and return memcpy(buf, CF_Q_ELEM_PTR(q, found_index), q->elementsz); cf_queue_delete_offset(q, found_index); } if (priority_q->threadsafe && (0 != pthread_mutex_unlock(&priority_q->LOCK))) { return(-1); } if (found_index == -1) return(CF_QUEUE_NOMATCH); return(0); }