1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 #include <sys/types.h>
  17 #include <sys/kmem.h>
  18 #include <sys/ddi.h>
  19 #include <sys/sunddi.h>
  20 #include <sys/time.h>
  21 #include <sys/sysmacros.h>
  22 #include <sys/debug.h>
  23 
  24 #include "krrp_queue.h"
  25 
  26 void
  27 krrp_queue_init(krrp_queue_t **queue, size_t obj_sz, size_t offset)
  28 {
  29         krrp_queue_t *qp;
  30 
  31         VERIFY(queue != NULL && *queue == NULL);
  32 
  33         qp = kmem_zalloc(sizeof (krrp_queue_t), KM_SLEEP);
  34 
  35         list_create(&qp->list, obj_sz, offset);
  36         qp->cnt = 0;
  37         qp->force_return = B_FALSE;
  38 
  39         mutex_init(&qp->mtx, NULL, MUTEX_DEFAULT, NULL);
  40         cv_init(&qp->cv, NULL, CV_DEFAULT, NULL);
  41 
  42         *queue = qp;
  43 }
  44 
  45 void
  46 krrp_queue_fini(krrp_queue_t *queue)
  47 {
  48         mutex_enter(&queue->mtx);
  49 
  50         VERIFY(queue->cnt == 0);
  51         list_destroy(&queue->list);
  52 
  53         mutex_exit(&queue->mtx);
  54 
  55         cv_destroy(&queue->cv);
  56         mutex_destroy(&queue->mtx);
  57 
  58         kmem_free(queue, sizeof (krrp_queue_t));
  59 }
  60 
  61 size_t
  62 krrp_queue_length(krrp_queue_t *queue)
  63 {
  64         size_t length = 0;
  65 
  66         mutex_enter(&queue->mtx);
  67         length = queue->cnt;
  68         mutex_exit(&queue->mtx);
  69 
  70         return (length);
  71 }
  72 
  73 void
  74 krrp_queue_set_force_return(krrp_queue_t *queue)
  75 {
  76         mutex_enter(&queue->mtx);
  77         queue->force_return = B_TRUE;
  78         cv_broadcast(&queue->cv);
  79         mutex_exit(&queue->mtx);
  80 }
  81 
  82 void
  83 krrp_queue_put(krrp_queue_t *queue, void *obj)
  84 {
  85         ASSERT(obj != NULL);
  86 
  87         mutex_enter(&queue->mtx);
  88         list_insert_head(&queue->list, obj);
  89         queue->cnt++;
  90         cv_broadcast(&queue->cv);
  91         mutex_exit(&queue->mtx);
  92 }
  93 
  94 void *
  95 krrp_queue_get(krrp_queue_t *queue)
  96 {
  97         void *obj;
  98         clock_t time_left = 0;
  99 
 100         mutex_enter(&queue->mtx);
 101 
 102         while ((obj = list_remove_tail(&queue->list)) == NULL) {
 103                 /*
 104                  * time_left < 0: timeout exceeded
 105                  */
 106                 if (queue->force_return || time_left < 0) {
 107                         mutex_exit(&queue->mtx);
 108                         return (NULL);
 109                 }
 110 
 111                 time_left = cv_reltimedwait(&queue->cv, &queue->mtx,
 112                     MSEC_TO_TICK(10), TR_CLOCK_TICK);
 113         }
 114 
 115         queue->cnt--;
 116         mutex_exit(&queue->mtx);
 117 
 118         return (obj);
 119 }
 120 
 121 void *
 122 krrp_queue_get_no_wait(krrp_queue_t *queue)
 123 {
 124         void *obj;
 125 
 126         mutex_enter(&queue->mtx);
 127 
 128         obj = list_remove_tail(&queue->list);
 129         if (obj != NULL)
 130                 queue->cnt--;
 131 
 132         mutex_exit(&queue->mtx);
 133 
 134         return (obj);
 135 }