* NOTE: Must be called with tq->tq_lock held, returns a list_t which * is not attached to the free, work, or pending taskq lists. */
| 106 | * is not attached to the free, work, or pending taskq lists. |
| 107 | */ |
| 108 | static taskq_ent_t * |
| 109 | task_alloc(taskq_t *tq, uint_t flags, unsigned long *irqflags) |
| 110 | { |
| 111 | taskq_ent_t *t; |
| 112 | int count = 0; |
| 113 | |
| 114 | ASSERT(tq); |
| 115 | retry: |
| 116 | /* Acquire taskq_ent_t's from free list if available */ |
| 117 | if (!list_empty(&tq->tq_free_list) && !(flags & TQ_NEW)) { |
| 118 | t = list_entry(tq->tq_free_list.next, taskq_ent_t, tqent_list); |
| 119 | |
| 120 | ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC)); |
| 121 | ASSERT(!(t->tqent_flags & TQENT_FLAG_CANCEL)); |
| 122 | ASSERT(!timer_pending(&t->tqent_timer)); |
| 123 | |
| 124 | list_del_init(&t->tqent_list); |
| 125 | return (t); |
| 126 | } |
| 127 | |
| 128 | /* Free list is empty and memory allocations are prohibited */ |
| 129 | if (flags & TQ_NOALLOC) |
| 130 | return (NULL); |
| 131 | |
| 132 | /* Hit maximum taskq_ent_t pool size */ |
| 133 | if (tq->tq_nalloc >= tq->tq_maxalloc) { |
| 134 | if (flags & TQ_NOSLEEP) |
| 135 | return (NULL); |
| 136 | |
| 137 | /* |
| 138 | * Sleep periodically polling the free list for an available |
| 139 | * taskq_ent_t. Dispatching with TQ_SLEEP should always succeed |
| 140 | * but we cannot block forever waiting for an taskq_ent_t to |
| 141 | * show up in the free list, otherwise a deadlock can happen. |
| 142 | * |
| 143 | * Therefore, we need to allocate a new task even if the number |
| 144 | * of allocated tasks is above tq->tq_maxalloc, but we still |
| 145 | * end up delaying the task allocation by one second, thereby |
| 146 | * throttling the task dispatch rate. |
| 147 | */ |
| 148 | spin_unlock_irqrestore(&tq->tq_lock, *irqflags); |
| 149 | schedule_timeout(HZ / 100); |
| 150 | spin_lock_irqsave_nested(&tq->tq_lock, *irqflags, |
| 151 | tq->tq_lock_class); |
| 152 | if (count < 100) { |
| 153 | count++; |
| 154 | goto retry; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | spin_unlock_irqrestore(&tq->tq_lock, *irqflags); |
| 159 | t = kmem_alloc(sizeof (taskq_ent_t), task_km_flags(flags)); |
| 160 | spin_lock_irqsave_nested(&tq->tq_lock, *irqflags, tq->tq_lock_class); |
| 161 | |
| 162 | if (t) { |
| 163 | taskq_init_ent(t); |
| 164 | tq->tq_nalloc++; |
| 165 | } |
no test coverage detected