Beispiel #1
0
 int futex_wait(fsem_t* p, const timespec* end_time)
 {
   int err = 0;
   timespec remain;
   if (decrement_if_positive(&p->val_) > 0)
   {}
   else
   {
     __sync_fetch_and_add(&p->nwaiters_, 1);
     while(1)
     {
       calc_remain_timespec(&remain, end_time);
       if (remain.tv_sec < 0)
       {
         err = ETIMEDOUT;
         break;
       }
       if (0 != futex(&p->val_, FUTEX_WAIT, 0, &remain, NULL, 0))
       {
         err = errno;
       }
       if (0 != err && EWOULDBLOCK != err && EINTR != err)
       {
         break;
       }
       if (decrement_if_positive(&p->val_) > 0)
       {
         err = 0;
         break;
       }
     }
     __sync_fetch_and_add(&p->nwaiters_, -1);
   }
   return err;
 }
Beispiel #2
0
void shared_mutex::imp_wait()
{
#ifdef _WIN32
	NtWaitForKeyedEvent(nullptr, &m_value, false, nullptr);
#else
	while (true)
	{
		// Load new value, try to acquire c_sig
		auto [value, ok] = m_value.fetch_op([](u32& value)
		{
			if (value >= c_sig)
			{
				value -= c_sig;
				return true;
			}

			return false;
		});

		if (ok)
		{
			return;
		}

		futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, nullptr, c_sig);
	}
#endif
}
Beispiel #3
0
// Thread spamming us with signals
void *sig_thread(void *arg)
{
	int *done = (int*)arg;
	struct sigaction sigact = {.sa_handler = sig_handler, 0};

	sigaction(SIGUSR1, &sigact, 0);
	while(1) {
		kill(getpid(), SIGUSR1);
		cmb();
		if (*done) return NULL;
	}
}

int main(int argc, char **argv)
{
	int done = false;

	pthread_t pth_handle, pth_handle2;
	// Spawn off a thread to spam us with signals
	pthread_create(&pth_handle, NULL, &sig_thread, &done);
	// Spawn off a thread to process those signals
	pthread_create(&pth_handle2, NULL, &count_signals, NULL);

	// Sleep for 3 seconds by timing out on a futex
	int dummy = 0;
	struct timespec timeout = {.tv_sec = 3, 0};

	futex(&dummy, FUTEX_WAIT, 0, &timeout, NULL, 0);
	// Force the signal tread to exit
	cmb();
	done = true;
	pthread_join(pth_handle, NULL);
	printf("count: %d\n", count);
	return 0;
}
Beispiel #4
0
void *count_signals(void *arg) {
	while(1) {
		futex(&__sigpending, FUTEX_WAIT, 0, NULL, NULL, 0);
		__sync_fetch_and_add(&count, 1);
		__sigpending = 0;
	}
}
Beispiel #5
0
 int futex_wait(fsem_t* p)
 {
   int err = 0;
   if (decrement_if_positive(&p->val_) > 0)
   {}
   else
   {
     __sync_fetch_and_add(&p->nwaiters_, 1);
     while(1)
     {
       if (0 != futex(&p->val_, FUTEX_WAIT, 0, NULL, NULL, 0))
       {
         err = errno;
       }
       if (0 != err && EWOULDBLOCK != err && EINTR != err)
       {
         break;
       }
       if (decrement_if_positive(&p->val_) > 0)
       {
         err = 0;
         break;
       }
     }
     __sync_fetch_and_add(&p->nwaiters_, -1);
   }
   return err;
 }
Beispiel #6
0
// Atomically,
//	if(*addr == val) sleep
// Might be woken up spuriously; that's allowed.
static void
futexsleep(uint32 *addr, uint32 val)
{
	// Some Linux kernels have a bug where futex of
	// FUTEX_WAIT returns an internal error code
	// as an errno.  Libpthread ignores the return value
	// here, and so can we: as it says a few lines up,
	// spurious wakeups are allowed.
	futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
}
void ThreadEntry::Wait(int value) {
  timespec ts;
  ts.tv_sec = 10;
  ts.tv_nsec = 0;
  errno = 0;
  futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
  if (errno != 0 && errno != EWOULDBLOCK) {
    BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
  }
}
Beispiel #8
0
void shared_mutex::imp_signal()
{
#ifdef _WIN32
	NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
#else
	m_value += c_sig;
	futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
	//futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, nullptr, c_sig - 1);
#endif
}
Beispiel #9
0
void testcase(unsigned long long *iterations)
{
	while (1) {
		unsigned int addr = 0;

		futex(&addr, FUTEX_WAIT_PRIVATE, 1, NULL, NULL, 0);

		(*iterations)++;
	}
}
Beispiel #10
0
int do_unlock_contended_pi_futex(void)
{
	if (futex(&pi_futex->counter, FUTEX_UNLOCK_PI, 1, NULL, NULL, 0) == 0)
		return 0;

	/*
	 * There are still some lower priority waiters we failed to
	 * wake for some reason. Documentation/pi-futex.txt fails
	 * to mention what FUTEX_UNLOCK_PI returns!
	 */
	switch(errno) {
	case ERESTART:
	case EINTR:
		log("INFO", "retrying release_pi_futex since interrupted\n");
		return 1;
	case EFAULT: /* We specified the wrong pi_futex address. */
		log("FAIL", "wrong futex address or page fault/futex race in-kernel.\n");
		break;
	case EINVAL:
		/*
		 * The old value is wrong. We should never
		 * get this since the kernel ignores the val
		 * passed through sys_futex().
		 */
		log("FAIL", "kernel got confused and lost the old futex value.\n");
		break;
	case EPERM:
		/*
		 * We are unable to release the futex.
		 * We may not be holding it like we think
		 * we do.
		 */
		log_error("This process seems to lack permission to release a futex it expects to be holding. Maybe it's not being held?\n");
		break;
	case EAGAIN:
		/*
		 * Task holding the futex is exiting. Odd,
		 * that's us!
		 */
		log("FAIL", "kernel insists we're exiting but we're really not!\n");
		break;
	case ENOMEM:
		log_error("");
		break;
	case ESRCH:
		/*
		 * Task that held the futex is no more?! But
		 * that's us!
		 */
		log("FAIL", "The kernel can't seem to find this process! I sense impending doom!\n");
		break;
	}

	return -1;
}
Beispiel #11
0
void shared_mutex::imp_lock_unlock()
{
	u32 _max = 1;

	for (int i = 0; i < 30; i++)
	{
		const u32 val = m_value;

		if (val % c_one == 0 && (val / c_one < _max || val >= c_sig))
		{
			// Return if have cought a state where:
			// 1) Mutex is free
			// 2) Total number of waiters decreased since last check
			// 3) Signal bit is set (if used on the platform)
			return;
		}

		_max = val / c_one;

		busy_wait(1500);
	}

#ifndef _WIN32
	while (false)
	{
		const u32 val = m_value;

		if (val % c_one == 0 && (val / c_one < _max || val >= c_sig))
		{
			return;
		}

		if (val <= c_one)
		{
			// Can't expect a signal
			break;
		}

		_max = val / c_one;

		// Monitor all bits except c_sig
		futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, val, nullptr, nullptr, c_sig - 1);
	}
#endif

	// Lock and unlock
	if (!m_value.fetch_add(c_one))
	{
		unlock();
		return;
	}

	imp_wait();
	unlock();
}
Beispiel #12
0
bool cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
{
	verify(HERE), _old != -1; // Very unlikely: it requires 2^32 distinct threads to wait simultaneously

#ifdef _WIN32
	LARGE_INTEGER timeout;
	timeout.QuadPart = _timeout * -10;

	if (HRESULT rc = NtWaitForKeyedEvent(nullptr, &m_value, false, _timeout == -1 ? nullptr : &timeout))
	{
		verify(HERE), rc == WAIT_TIMEOUT;

		// Retire
		if (!m_value.fetch_op([](u32& value) { if (value) value--; }))
		{
			NtWaitForKeyedEvent(nullptr, &m_value, false, nullptr);
			return true;
		}

		return false;
	}

	return true;
#elif __linux__
	timespec timeout;
	timeout.tv_sec  = _timeout / 1000000;
	timeout.tv_nsec = (_timeout % 1000000) * 1000;

	for (u32 value = _old + 1;; value = m_value)
	{
		const int err = futex((int*)&m_value.raw(), FUTEX_WAIT_PRIVATE, value, _timeout == -1 ? nullptr : &timeout, nullptr, 0) == 0
			? 0
			: errno;

		// Normal or timeout wakeup
		if (!err || (_timeout != -1 && err == ETIMEDOUT))
		{
			// Cleanup (remove waiter)
			verify(HERE), m_value--;
			return !err;
		}

		// Not a wakeup
		verify(HERE), err == EAGAIN;
	}
#else
	// TODO
	std::this_thread::sleep_for(std::chrono::microseconds(50));
	verify(HERE), m_value--;
	return true;
#endif
}
static inline void futex_wait(QemuEvent *ev, unsigned val)
{
    while (futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0)) {
        switch (errno) {
        case EWOULDBLOCK:
            return;
        case EINTR:
            break; /* get out of switch and retry */
        default:
            abort();
        }
    }
}
Beispiel #14
0
int bbgl_mutex_unlock(bbgl_mutex_t *mutex) {
    if (*mutex == 2)
        *mutex = 0;
    else if (xchg(mutex, 0) == 1)
        return 0;
    for (int i = 0; i < 200; i++) {
        if (*mutex)
            if (cmpxchg(mutex, 1, 2))
                return 0;
        __asm__ __volatile__("pause" ::: "memory");
    }
    futex(mutex, FUTEX_WAKE, 1, NULL, NULL, 0);
    return 0;
}
Beispiel #15
0
void cond_variable::imp_wake(u32 _count) noexcept
{
#ifdef _WIN32
	// Try to subtract required amount of waiters
	const u32 count = m_value.atomic_op([=](u32& value)
	{
		if (value > _count)
		{
			value -= _count;
			return _count;
		}

		return std::exchange(value, 0);
	});

	for (u32 i = count; i > 0; i--)
	{
		NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
	}
#elif __linux__
	for (u32 i = _count; i > 0; sched_yield())
	{
		const u32 value = m_value;

		// Constrain remaining amount with imaginary waiter count
		if (i > value)
		{
			i = value;
		}

		if (!value || i == 0)
		{
			// Nothing to do
			return;
		}

		if (const int res = futex((int*)&m_value.raw(), FUTEX_WAKE_PRIVATE, i > INT_MAX ? INT_MAX : i, nullptr, nullptr, 0))
		{
			verify(HERE), res >= 0 && res <= i;
			i -= res;
		}

		if (!m_value || i == 0)
		{
			// Escape
			return;
		}
	}
#endif
}
Beispiel #16
0
/* futex post & wait */
void wait_futex_sem(struct lockinfo *l)
{
	int ret;
	l->data = 1;
	worklist_add(l);
	while(l->data == 1) {
		ret = futex(&l->data, FUTEX_WAIT, 1, NULL, NULL, 0);
		/*
		if (ret && ret != EWOULDBLOCK) {
			perror("futex wait");
			exit(1);
		}*/
	}
}
Beispiel #17
0
// If any procs are sleeping on addr, wake up at most cnt.
static void
futexwakeup(uint32 *addr, uint32 cnt)
{
	int64 ret;

	ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0);

	if(ret >= 0)
		return;

	// I don't know that futex wakeup can return
	// EAGAIN or EINTR, but if it does, it would be
	// safe to loop and call futex again.
	runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret);
	*(int32*)0x1006 = 0x1006;
}
Beispiel #18
0
int bbgl_mutex_lock(bbgl_mutex_t *mutex) {
    int c;
    for (int i = 0; i < 100; i++) {
        c = cmpxchg(mutex, 0, 1);
        if (c == 0)
            return 0;
        __asm__ __volatile__("pause" ::: "memory");
    }
    if (c == 1)
        c = xchg(mutex, 2);
    while (c) {
        futex(mutex, FUTEX_WAIT, 2, NULL, NULL, 0);
        c = xchg(mutex, 2);
    }
    return 0;
}
Beispiel #19
0
int main(int argc, char *argv[]) {
	const size_t stack_size = 1 << 20;
	void* stack = mmap(NULL, stack_size,
			   PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
			   -1, 0);
	int pid;
	sigset_t set;

	sys_gettid();
	/* NB: no syscalls in between the sys_gettid() above and this
	 * clone(). */
	breakpoint();

	/* Warning: strace gets the parameter order wrong and will print
	   child_tidptr as 0 here. */
	pid = clone(child, stack + stack_size,
		CLONE_VM | CLONE_FS | CLONE_FILES |
		CLONE_THREAD | CLONE_SIGHAND |
		CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID,
		NULL, &child_tid, NULL, &child_tid);

	atomic_printf("clone()d pid: %d\n", pid);
	test_assert(pid > 0);

	futex(&child_tid, FUTEX_WAIT, pid, NULL, NULL, 0);
	test_assert(child_tid_copy == pid);
	/* clone() should have cleared child_tid now */
	test_assert(child_tid == 0);

	sys_gettid();

	sigfillset(&set);
	test_assert(0 == sigprocmask(SIG_BLOCK, &set, NULL));

	/* NB: no syscalls in between the sys_gettid() above and this
	 * clone(). */
	breakpoint();
	pid = clone(child, stack + stack_size,
		    CLONE_SIGHAND /*must also have CLONE_VM*/,
		    NULL, NULL, NULL);

	atomic_printf("clone(CLONE_SIGHAND)'d pid: %d\n", pid);
	test_assert(-1 == pid);

	atomic_puts("EXIT-SUCCESS");
	return 0;
}
Beispiel #20
0
 int futex_post(fsem_t* p)
 {
   int err = 0;
   if (__sync_fetch_and_add(&p->val_, 1) >= INT_MAX)
   {
     err = EOVERFLOW;
   }
   else
   {
     __sync_synchronize(); // 这个barrier完全是从glibc中抄过来的,其实可以不要。
     if (p->nwaiters_ > 0)
     {
       futex(&p->val_, FUTEX_WAKE, 1, NULL, NULL, 0);
     }
   }
   return err;
 }
Beispiel #21
0
int kid(void *trash)
{
	atomic_inc(&dumb_barrier[0]); /* 1 */
again:
	if (futex(&test_futex->counter, FUTEX_WAIT, -1, NULL, NULL, 0) != 0) {
		switch(errno) {
			case ETIMEDOUT:
				log_error("FUTEX_WAIT ETIMEDOUT");
				break;
			case ERESTART:
				log("INFO", "RESTARTING FUTEX_WAIT (I think I was FROZEN)");
				goto again;
			case EAGAIN: /* EWOULDBLOCK */
				if (atomic_read(test_futex) == 1) {
					log("INFO", "kid: I was interrupted.\n");
					log("INFO", "kid: and now test_futex==1, so I'm done\n");
					break;
				}
				log("INFO", "FUTEX_WAIT EAGAIN");
				goto again;
				break;
			case EINTR:
				log("INFO", "FUTEX_WAIT EINTR");
				goto again;
				break;
			case EACCES:
				log("FAIL", "FUTEX_WAIT EACCES - no read access to futex memory\n");
				break;
			case EFAULT:
				log("FAIL", "FUTEX_WAIT EFAULT - bad timeout timespec address or futex address\n");
				break;
			case EINVAL:
				log("FAIL", "FUTEX_WAIT EINVAL - undefined futex operation\n");
				break;
			case ENOSYS:
				log("FAIL", "FUTEX_WAIT ENOSYS - undefined futex operation\n");
				break;
			default:
				log_error("FUTEX_WAIT unexpected error (missing from man page)");
				break;
		}
	}
	atomic_inc(&dumb_barrier[1]); /* 2 */
	return 0;
}
Beispiel #22
0
// Atomically,
//	if(*addr == val) sleep
// Might be woken up spuriously; that's allowed.
static void
futexsleep(uint32 *addr, uint32 val)
{
	int32 ret;

	ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
	if(ret >= 0 || ret == -EAGAIN || ret == -EINTR)
		return;

	prints("futexsleep addr=");
	·printpointer(addr);
	prints(" val=");
	·printint(val);
	prints(" returned ");
	·printint(ret);
	prints("\n");
	*(int32*)0x1005 = 0x1005;
}
Beispiel #23
0
int wake_waitq(atomic_t *wq, int retries)
{
	unsigned int woken = 0;
	int ret;

	atomic_set(wq, 1);
	do {
		ret = futex(&wq->counter, FUTEX_WAKE, N - 1 - woken, NULL, NULL, 0);
		retries--;
		if (ret > 0)
			woken += ret;
	} while (retries && woken < N - 1);

	if (woken < N - 1) {
		log("WARN", "Could not wake %d children. Woke %d instead. waitq: %d\n", N - 1, woken, atomic_read(waitq));
		log_error("     ");
	}
	return -1;
}
Beispiel #24
0
// If any procs are sleeping on addr, wake up at least one.
static void
futexwakeup(uint32 *addr)
{
	int64 ret;

	ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);

	if(ret >= 0)
		return;

	// I don't know that futex wakeup can return
	// EAGAIN or EINTR, but if it does, it would be
	// safe to loop and call futex again.

	prints("futexwakeup addr=");
	·printpointer(addr);
	prints(" returned ");
	·printint(ret);
	prints("\n");
	*(int32*)0x1006 = 0x1006;
}
Beispiel #25
0
void *handler(void *arg) {
	int id = pthread_self()->id;
	int var = 0;
    struct timespec timeout = {
		.tv_sec = id,
		.tv_nsec = 0
	};
	printf("Begin thread: %d\n", id);
    futex(&var, FUTEX_WAIT, 0, &timeout, NULL, 0);
	printf("End thread: %d\n", id);
}

int main(int argc, char **argv)
{
	for (int i=0; i<NUM_THREADS; i++) {
		pthread_create(&thandlers[i], NULL, &handler, NULL);
	}
	for (int i=0; i<NUM_THREADS; i++) {
		pthread_join(thandlers[i], NULL);
	}
	return 0;
}
Beispiel #26
0
int futex_wake_some(struct sem_wakeup_info *wi, int num_semids, int num)
{
	int i;
	int ret;
	struct lockinfo *l;
	int found = 0;

	for (i = 0; i < num; i++) {
		l = worklist_rm();
		if (!l)
			break;
		if (l->data != 1)
			fprintf(stderr, "warning, lockinfo data was %d\n",
				l->data);
		l->data = 0;
		ret = futex(&l->data, FUTEX_WAKE, 1, NULL, NULL, 0);
		if (ret < 0) {
			perror("futex wake");
			exit(1);
		}
		found++;
	}
	return found;
}
Beispiel #27
0
int os_futex_wake(int *address, int count) {
    return futex(address, FUTEX_WAKE, count, nullptr, nullptr, 0) ? errno : 0;
}
Beispiel #28
0
int os_futex_wait(int *address, int val) {
    return futex(address, FUTEX_WAIT, val, nullptr, nullptr, 0) ? errno : 0;
}
Beispiel #29
0
int main(int argc, char **argv)
{
	pid_t kids[N];
	int i, num_killed = 0, excode = EXIT_FAILURE;
	char *freezerdir;

	if (argc < 2)
		exit(1);
	freezerdir = argv[1];

	if (!move_to_cgroup("freezer", freezerdir, getpid())) {
		printf("Failed to move myself to cgroup\n");
		exit(1);
	}
	/* FIXME eventually stdio streams should be harmless */
	close(0);
	logfp = fopen(LOG_FILE, "w");
	if (!logfp) {
		perror("could not open logfile");
		exit(1);
	}
	dup2(fileno(logfp), 1); /* redirect stdout and stderr to the log file */
	dup2(fileno(logfp), 2);

	test_futex = alloc_futex_mem(sizeof(*test_futex));
	if (!test_futex) {
		log_error("alloc_futex_mem");
		exit(3);
	}
	atomic_set(test_futex, -1);

	signal(SIGINT, sig_dump);
	for (i = 0; i < N; i++) {
		char *new_stack = malloc(SIGSTKSZ*8);
		if (!new_stack) {
			i--;
			break;
		}
		kids[i] = clone(kid, new_stack + SIGSTKSZ*8, clone_flags,
				NULL);
		if (kids[i] < 0) {
			i--;
			break;
		}
	}

	if (i < N) {
		log_error("N x FUTEX_WAIT");
		log("INFO", "killing %d child tasks.\n", i);
		for (; --i > -1;)
			kill(kids[i], SIGTERM);
		_exit(4);
	}

	/* parent */
	log("INFO", "Waiting for children to sleep on futex\n");
	while (atomic_read(&dumb_barrier[0]) != N) /* 1 */
		sleep(1);
	dump("After 1, before 2:");

	sleep(1);
	log("INFO", "signaling ready for checkpointing\n");
	set_checkpoint_ready();
	while (!test_checkpoint_done()) { sleep(1); }

	log("INFO", "Parent woken\n");
	atomic_set(test_futex, 1);
	dump("After 1, cleared test_futex, before 2:");
	i = futex(&test_futex->counter, FUTEX_WAKE, N, NULL, NULL, 0);
	if (i == -1) {
		fprintf(logfp, "futex_wake N=%d returned %d\n", N, i);
		log_error("FUTEX_WAKE");
		sleep(1); /* wait for all woken tasks to exit quietly */

		/* kill the rest */
		for (i = 0; i < N; i++) {
			if (kill(kids[i], SIGKILL) == 0)
				num_killed++;
		}
		if (num_killed)
			log("INFO", "killed %d remaining child tasks.\n",
				num_killed);
	} else
		excode = EXIT_SUCCESS;
	dump("After 2:");

	do_wait(N);
	dump("After 3:");
	fclose(logfp);
	exit(excode);
}
void ThreadEntry::Wake() {
  futex_++;
  futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
}