#ifndef _LINUX_COMPLETION_H_
#define _LINUX_COMPLETION_H_
#include <linux/wait.h>
#include <linux/errno.h>
#include <sys/kernel.h>
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
static inline void
init_completion(struct completion *c)
{
c->done = 0;
init_waitqueue_head(&c->wait);
}
static inline void
reinit_completion(struct completion *c)
{
c->done = 0;
}
#define INIT_COMPLETION(c) (c.done = 0)
static inline void
complete(struct completion *c)
{
lockmgr(&c->wait.lock, LK_EXCLUSIVE);
if (c->done != UINT_MAX)
c->done++;
lockmgr(&c->wait.lock, LK_RELEASE);
wakeup_one(&c->wait);
}
static inline void
complete_all(struct completion *c)
{
lockmgr(&c->wait.lock, LK_EXCLUSIVE);
c->done = UINT_MAX;
lockmgr(&c->wait.lock, LK_RELEASE);
wakeup(&c->wait);
}
static inline long
__wait_for_completion_generic(struct completion *c,
unsigned long timeout, int flags)
{
int start_jiffies, elapsed_jiffies, remaining_jiffies;
bool timeout_expired = false, awakened = false;
long ret = 1;
start_jiffies = ticks;
lockmgr(&c->wait.lock, LK_EXCLUSIVE);
while (c->done == 0 && !timeout_expired) {
ret = lksleep(&c->wait, &c->wait.lock, flags, "lwfcg", timeout);
switch(ret) {
case EWOULDBLOCK:
timeout_expired = true;
ret = 0;
break;
case ERESTART:
ret = -ERESTARTSYS;
break;
case 0:
awakened = true;
break;
}
}
if (c->done && c->done != UINT_MAX)
--c->done;
lockmgr(&c->wait.lock, LK_RELEASE);
if (awakened) {
elapsed_jiffies = ticks - start_jiffies;
remaining_jiffies = timeout - elapsed_jiffies;
if (remaining_jiffies > 0)
ret = remaining_jiffies;
}
return ret;
}
int wait_for_completion_interruptible(struct completion *c);
static inline long
wait_for_completion_interruptible_timeout(struct completion *c,
unsigned long timeout)
{
return __wait_for_completion_generic(c, timeout, PCATCH);
}
static inline unsigned long
wait_for_completion_timeout(struct completion *c, unsigned long timeout)
{
return __wait_for_completion_generic(c, timeout, 0);
}
void wait_for_completion(struct completion *c);
static inline bool
try_wait_for_completion(struct completion *c)
{
bool ret = false;
if (READ_ONCE(c->done) == 0)
return false;
lockmgr(&c->wait.lock, LK_EXCLUSIVE);
if (c->done > 0) {
c->done--;
ret = true;
}
lockmgr(&c->wait.lock, LK_RELEASE);
return ret;
}
#endif