Implement tryadd, adding itmes with a timeout

This commit is contained in:
Nils O. Selåsdal
2013-01-02 16:54:20 +01:00
parent dbe91d2d13
commit 3e7fd8a34b
3 changed files with 99 additions and 6 deletions
+10 -2
View File
@@ -166,11 +166,19 @@ int uc_thread_queue_init(struct uc_threadqueue *queue, long max_elements);
* the front of the queue, i.e. it can be considered a "priority" message. * the front of the queue, i.e. it can be considered a "priority" message.
* *
* @param queue Pointer to the queue on where the message should be added. * @param queue Pointer to the queue on where the message should be added.
* @param timeout timeout on how long to wait on a message, or NULL for no timeout
* @param data the "message". * @param data the "message".
* @return 0 on succes ENOMEM if out of memory EINVAL if queue is NULL, or other * @return 0 on succes ENOMEM if out of memory EINVAL if queue is NULL, ETIMEDOUT if timeout occured or other
* errno values if pthread functions failed. * errno values if pthread functions failed.
*/ */
int uc_thread_queue_add(struct uc_threadqueue *queue, struct uc_threadmsg *msg); int uc_thread_queue_tryadd(struct uc_threadqueue *queue, const struct timespec *timeout, struct uc_threadmsg *msg);
/**
* Like uc_thread_queue_add but will wait indefintly.
* @see uc_thread_queue_add
*/
#define uc_thread_queue_add(queue, msg)\
uc_thread_queue_tryadd(queue, NULL, msg)
/** /**
* Gets a message from a queue * Gets a message from a queue
+25 -2
View File
@@ -57,21 +57,44 @@ int uc_thread_queue_init(struct uc_threadqueue *queue, long max_elements)
return rc; return rc;
} }
int uc_thread_queue_add(struct uc_threadqueue *queue, struct uc_threadmsg *msg) int uc_thread_queue_tryadd(struct uc_threadqueue *queue, const struct timespec *timeout, struct uc_threadmsg *msg)
{ {
int rc = 0;
struct timespec abstimeout;
if (queue == NULL || msg == NULL) { if (queue == NULL || msg == NULL) {
return EINVAL; return EINVAL;
} }
if (timeout) {
uc_get_absolute_time(&abstimeout, timeout);
}
pthread_mutex_lock(&queue->mutex); pthread_mutex_lock(&queue->mutex);
//Wait if the queue is full //Wait if the queue is full
while(queue->num_elements >= queue->max_elements) { while(queue->num_elements >= queue->max_elements && rc != ETIMEDOUT) {
queue->num_write_waiters++; queue->num_write_waiters++;
if(timeout) {
//fastpath, check for a poll
if(timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
rc = ETIMEDOUT;
} else {
rc = pthread_cond_timedwait(&queue->write_cond, &queue->mutex, &abstimeout);
}
} else {
pthread_cond_wait(&queue->write_cond, &queue->mutex); pthread_cond_wait(&queue->write_cond, &queue->mutex);
}
queue->num_write_waiters--; queue->num_write_waiters--;
} }
if (rc == ETIMEDOUT) {
pthread_mutex_unlock(&queue->mutex);
return rc;
}
//insert the new element //insert the new element
msg->next = NULL; msg->next = NULL;
if (msg->msgtype >= 0) { //add at the tail if (msg->msgtype >= 0) { //add at the tail
+62
View File
@@ -55,6 +55,8 @@ START_TEST (test_thread_queue_one_thread)
END_TEST END_TEST
//pretty ugly.. //pretty ugly..
static int test_thread_queue_walk_global; static int test_thread_queue_walk_global;
static void test_thread_queue_walk_func(struct uc_threadmsg *msg) static void test_thread_queue_walk_func(struct uc_threadmsg *msg)
@@ -253,6 +255,63 @@ START_TEST (test_thread_queue_timeout2)
END_TEST END_TEST
START_TEST (test_thread_queue_tryadd_timeout_0_0)
struct uc_threadqueue queue;
int i;
struct thr_msg msg[3];
memset(msg, 0, sizeof msg);
struct timespec timeout = {0,0};
fail_if(uc_thread_queue_init(&queue, 2) != 0);
for (i = 0; i < 2; i++) {
fail_if(uc_thread_queue_add(&queue, &msg[i].msg) != 0);
}
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != ETIMEDOUT);
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
END_TEST
START_TEST (test_thread_queue_tryadd_timeout_0_100)
struct uc_threadqueue queue;
int i;
struct thr_msg msg[3];
memset(msg, 0, sizeof msg);
struct timespec timeout = {0,100};
fail_if(uc_thread_queue_init(&queue, 2) != 0);
for (i = 0; i < 2; i++) {
fail_if(uc_thread_queue_add(&queue, &msg[i].msg) != 0);
}
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != ETIMEDOUT);
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
END_TEST
START_TEST (test_thread_queue_tryadd_no_timeout_0_100)
struct uc_threadqueue queue;
int i;
struct thr_msg msg[3];
memset(msg, 0, sizeof msg);
struct timespec timeout = {0,100};
fail_if(uc_thread_queue_init(&queue, 3) != 0);
for (i = 0; i < 2; i++) {
fail_if(uc_thread_queue_add(&queue, &msg[i].msg) != 0);
}
fail_if(uc_thread_queue_tryadd(&queue, &timeout, &msg[2].msg) != 0);
fail_if(uc_thread_queue_destroy(&queue, NULL) != 0);
END_TEST
Suite *threadqueue_suite(void) Suite *threadqueue_suite(void)
{ {
@@ -268,6 +327,9 @@ Suite *threadqueue_suite(void)
tcase_add_test(tc1, test_thread_queue_multiple_writers); tcase_add_test(tc1, test_thread_queue_multiple_writers);
tcase_add_test(tc1, test_thread_queue_timeout1); tcase_add_test(tc1, test_thread_queue_timeout1);
tcase_add_test(tc1, test_thread_queue_timeout2); tcase_add_test(tc1, test_thread_queue_timeout2);
tcase_add_test(tc1, test_thread_queue_tryadd_timeout_0_0);
tcase_add_test(tc1, test_thread_queue_tryadd_timeout_0_100);
tcase_add_test(tc1, test_thread_queue_tryadd_no_timeout_0_100);
//lets start with this: //lets start with this:
tcase_set_timeout(tc1, 15); tcase_set_timeout(tc1, 15);