Пример #1
0
void
__go_builtin_close (struct __go_channel *channel)
{
  int i;

  i = pthread_mutex_lock (&channel->lock);
  __go_assert (i == 0);

  while (channel->selected_for_send)
    {
      i = pthread_cond_wait (&channel->cond, &channel->lock);
      __go_assert (i == 0);
    }

  if (channel->is_closed)
    {
      i = pthread_mutex_unlock (&channel->lock);
      __go_assert (i == 0);
      __go_panic_msg ("close of closed channel");
    }

  channel->is_closed = 1;

  i = pthread_cond_broadcast (&channel->cond);
  __go_assert (i == 0);

  __go_unlock_and_notify_selects (channel);
}
void
runtime_semrelease (uint32 *addr)
{
    int32_t val;

    val = __sync_fetch_and_add (addr, 1);

    /* VAL is the old value.  It should never be negative.  If it is
       negative, that implies that Semacquire somehow decremented a zero
       value, or that the count has overflowed.  */
    __go_assert (val >= 0);

    /* If the old value was zero, then we have now released a count, and
       we signal the condition variable.  If the old value was positive,
       then nobody can be waiting.  We have to use
       pthread_cond_broadcast, not pthread_cond_signal, because
       otherwise there would be a race condition when the count is
       incremented twice before any locker manages to decrement it.  */
    if (val == 0)
    {
        int i;

        i = pthread_mutex_lock (&sem_lock);
        __go_assert (i == 0);

        i = pthread_cond_broadcast (&sem_cond);
        __go_assert (i == 0);

        i = pthread_mutex_unlock (&sem_lock);
        __go_assert (i == 0);
    }
}
Пример #3
0
void
__go_receive_release (struct __go_channel *channel)
{
    int i;

    if (channel->num_entries != 0)
        channel->next_fetch = (channel->next_fetch + 1) % channel->num_entries;
    else
    {
        /* For a synchronous receiver, we tell the sender that we picked
        up the value by setting the next_store field back to 0.
         Using the mutexes should implement a memory barrier.  */
        __go_assert (channel->next_store == 1);
        channel->next_store = 0;

        channel->waiting_to_receive = 0;
    }

    channel->selected_for_receive = 0;

    /* This is a broadcast to make sure that a synchronous sender sees
       it.  */
    i = pthread_cond_broadcast (&channel->cond);
    __go_assert (i == 0);

    __go_unlock_and_notify_selects (channel);
}
Пример #4
0
static _Bool
mark_all_channels_waiting (struct select_channel* channels, size_t count,
			   struct __go_channel **selected_pointer,
			   _Bool *selected_for_read_pointer)
{
  _Bool ret;
  int x;
  size_t i;

  ret = 0;
  for (i = 0; i < count; ++i)
    {
      struct __go_channel *channel = channels[i].channel;
      _Bool is_send = channels[i].is_send;

      if (channel == NULL)
	continue;

      if (channels[i].dup_index != (size_t) -1UL)
	{
	  size_t j;

	  /* A channel may be selected for both read and write.  */
	  if (channels[channels[i].dup_index].is_send != is_send)
	    {
	      for (j = channels[i].dup_index + 1; j < i; ++j)
		{
		  if (channels[j].channel == channel
		      && channels[j].is_send == is_send)
		    break;
		}
	      if (j < i)
		continue;
	    }
	}

      x = pthread_mutex_lock (&channel->lock);
      __go_assert (x == 0);

      /* To avoid a race condition, we have to check again whether the
	 channel is ready.  It may have become ready since we did the
	 first set of checks but before we acquired the select mutex.
	 If we don't check here, we could sleep forever on the select
	 condition variable.  */
      if (is_channel_ready (channel, is_send))
	ret = 1;

      /* If SELECTED_POINTER is NULL, then we have already marked the
	 channel as waiting.  */
      if (selected_pointer != NULL)
	mark_select_waiting (&channels[i], selected_pointer,
			     selected_for_read_pointer);

      x = pthread_mutex_unlock (&channel->lock);
      __go_assert (x == 0);
    }

  return ret;
}
Пример #5
0
void *
__go_allocate_trampoline (uintptr_t size, void *closure)
{
  uintptr_t ptr_size;
  uintptr_t full_size;
  unsigned char *ret;

  /* Because the garbage collector only looks at aligned addresses, we
     need to store the closure at an aligned address to ensure that it
     sees it.  */
  ptr_size = sizeof (void *);
  full_size = (((size + ptr_size - 1) / ptr_size) * ptr_size);
  full_size += ptr_size;

  runtime_lock (&trampoline_lock);

  if (full_size < trampoline_page_size - trampoline_page_used)
    trampoline_page = NULL;

  if (trampoline_page == NULL)
    {
      uintptr_t page_size;
      unsigned char *page;

      page_size = getpagesize ();
      __go_assert (page_size >= full_size);
      page = (unsigned char *) runtime_mallocgc (2 * page_size - 1, 0, 0, 0);
      page = (unsigned char *) (((uintptr_t) page + page_size - 1)
				& ~ (page_size - 1));

#ifdef HAVE_SYS_MMAN_H
      {
	int i;

	i = mprotect (page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
	__go_assert (i == 0);
      }
#endif

      trampoline_page = page;
      trampoline_page_size = page_size;
      trampoline_page_used = 0;
    }

  ret = trampoline_page + trampoline_page_used;
  trampoline_page_used += full_size;

  runtime_unlock (&trampoline_lock);

  __builtin_memcpy (ret + full_size - ptr_size, &closure, ptr_size);

  return (void *) ret;
}
void
__go_send_acquire (struct __go_channel *channel, _Bool for_select)
{
  int i;

  i = pthread_mutex_lock (&channel->lock);
  __go_assert (i == 0);

  while (1)
    {
      if (channel->is_closed)
	{
	  if (for_select)
	    channel->selected_for_send = 0;
	  i = pthread_mutex_unlock (&channel->lock);
	  __go_assert (i == 0);
	  __go_panic_msg ("send on closed channel");
	}

      /* If somebody else has the channel locked for sending, we have
	 to wait.  If FOR_SELECT is true, then we are the one with the
	 lock.  */
      if (!channel->selected_for_send || for_select)
	{
	  if (channel->num_entries == 0)
	    {
	      /* This is a synchronous channel.  If nobody else is
		 waiting to send, we grab the channel and tell the
		 caller to send the data.  We will then wait for a
		 receiver.  */
	      if (!channel->waiting_to_send)
		{
		  __go_assert (channel->next_store == 0);
		  return;
		}
	    }
	  else
	    {
	      /* If there is room on the channel, we are OK.  */
	      if ((channel->next_store + 1) % channel->num_entries
		  != channel->next_fetch)
		return;
	    }
	}

      /* Wait for something to change, then loop around and try
	 again.  */

      i = pthread_cond_wait (&channel->cond, &channel->lock);
      __go_assert (i == 0);
    }
}
Пример #7
0
void
runtime_noteclear (Note* n)
{
  int32 i;

  i = pthread_mutex_lock (&note_lock);
  __go_assert (i == 0);

  n->woken = 0;

  i = pthread_mutex_unlock (&note_lock);
  __go_assert (i == 0);
}
Пример #8
0
uint64_t
__go_receive_small_closed (struct __go_channel *channel, _Bool for_select,
                           _Bool *received)
{
    uintptr_t element_size;
    uint64_t ret;

    if (channel == NULL)
        __go_panic_msg ("receive from nil channel");

    element_size = channel->element_type->__size;
    __go_assert (element_size <= sizeof (uint64_t));

    if (!__go_receive_acquire (channel, for_select))
    {
        if (received != NULL)
            *received = 0;
        return 0;
    }

    ret = channel->data[channel->next_fetch];

    __go_receive_release (channel);

    if (received != NULL)
        *received = 1;

    return ret;
}
Пример #9
0
void
runtime_notewakeup (Note *n)
{
  int32 i;

  i = pthread_mutex_lock (&note_lock);
  __go_assert (i == 0);

  n->woken = 1;

  i = pthread_cond_broadcast (&note_cond);
  __go_assert (i == 0);

  i = pthread_mutex_unlock (&note_lock);
  __go_assert (i == 0);
}
Пример #10
0
size_t
force_selected_channel_ready (struct select_channel *channels, size_t count,
			      struct __go_channel *selected_channel,
			      _Bool selected_for_read)
{
  size_t ready_count;
  size_t i;

  ready_count = 0;
  for (i = 0; i < count; ++i)
    {
      struct __go_channel *channel = channels[i].channel;
      _Bool is_send = channels[i].is_send;

      if (channel == NULL)
	continue;

      if (channel != selected_channel
	  || (is_send ? !selected_for_read : selected_for_read))
	channels[i].is_ready = 0;
      else
	{
	  channels[i].is_ready = 1;
	  ++ready_count;
	}
    }
  __go_assert (ready_count > 0);
  return ready_count;
}
Пример #11
0
uint64_t
__go_receive_small_closed (struct __go_channel *channel, _Bool for_select,
                           _Bool *received)
{
    uintptr_t element_size;
    uint64_t ret;

    if (channel == NULL)
    {
        /* Block forever.  */
        __go_select (0, 0, NULL, NULL);
    }

    element_size = channel->element_type->__size;
    __go_assert (element_size <= sizeof (uint64_t));

    if (!__go_receive_acquire (channel, for_select))
    {
        if (received != NULL)
            *received = 0;
        return 0;
    }

    ret = channel->data[channel->next_fetch];

    __go_receive_release (channel);

    if (received != NULL)
        *received = 1;

    return ret;
}
Пример #12
0
void *
__go_map_index (struct __go_map *map, const void *key, _Bool insert)
{
  const struct __go_map_descriptor *descriptor;
  const struct __go_type_descriptor *key_descriptor;
  uintptr_t key_offset;
  _Bool (*equalfn) (const void*, const void*, uintptr_t);
  size_t key_hash;
  size_t key_size;
  size_t bucket_index;
  char *entry;

  if (map == NULL)
    {
      if (insert)
	runtime_panicstring ("assignment to entry in nil map");
      return NULL;
    }

  descriptor = map->__descriptor;

  key_descriptor = descriptor->__map_descriptor->__key_type;
  key_offset = descriptor->__key_offset;
  key_size = key_descriptor->__size;
  __go_assert (key_size != 0 && key_size != -1UL);
  equalfn = key_descriptor->__equalfn;

  key_hash = key_descriptor->__hashfn (key, key_size);
  bucket_index = key_hash % map->__bucket_count;

  entry = (char *) map->__buckets[bucket_index];
  while (entry != NULL)
    {
      if (equalfn (key, entry + key_offset, key_size))
	return entry + descriptor->__val_offset;
      entry = *(char **) entry;
    }

  if (!insert)
    return NULL;

  if (map->__element_count >= map->__bucket_count)
    {
      __go_map_rehash (map);
      bucket_index = key_hash % map->__bucket_count;
    }

  entry = (char *) __go_alloc (descriptor->__entry_size);
  __builtin_memset (entry, 0, descriptor->__entry_size);

  __builtin_memcpy (entry + key_offset, key, key_size);

  *(char **) entry = map->__buckets[bucket_index];
  map->__buckets[bucket_index] = entry;

  map->__element_count += 1;

  return entry + descriptor->__val_offset;
}
uint32
__sync_fetch_and_add_4(uint32* ptr, uint32 add)
{
    int i;
    uint32 ret;

    i = pthread_mutex_lock(&sync_lock);
    __go_assert(i == 0);

    ret = *ptr;
    *ptr += add;

    i = pthread_mutex_unlock(&sync_lock);
    __go_assert(i == 0);

    return ret;
}
Пример #14
0
void
runtime_notesleep (Note* n)
{
  int32 i;

  i = pthread_mutex_lock (&note_lock);
  __go_assert (i == 0);

  while (!n->woken)
    {
      i = pthread_cond_wait (&note_cond, &note_lock);
      __go_assert (i == 0);
    }

  i = pthread_mutex_unlock (&note_lock);
  __go_assert (i == 0);
}
int
__go_map_len (struct __go_map *map)
{
  if (map == NULL)
    return 0;
  __go_assert (map->__element_count == (uintptr_t) (int) map->__element_count);
  return map->__element_count;
}
Пример #16
0
static void
sig_panic_leadin (int sig)
{
  int i;
  sigset_t clear;

  if (runtime_m ()->mallocing)
    {
      runtime_printf ("caught signal while mallocing: %d\n", sig);
      runtime_throw ("caught signal while mallocing");
    }

  /* The signal handler blocked signals; unblock them.  */
  i = sigfillset (&clear);
  __go_assert (i == 0);
  i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
  __go_assert (i == 0);
}
Пример #17
0
static void
sig_handler (int sig)
{
  int i;

#ifdef SIGPROF
  if (sig == SIGPROF)
    {
      /* FIXME.  */
      runtime_sigprof (0, 0, nil, nil);
      return;
    }
#endif

  for (i = 0; runtime_sigtab[i].sig != -1; ++i)
    {
      struct sigaction sa;
      SigTab *t;

      t = &runtime_sigtab[i];

      if (t->sig != sig)
	continue;

      if ((t->flags & SigNotify) != 0)
	{
	  if (__go_sigsend (sig))
	    return;
	}
      if ((t->flags & SigKill) != 0)
	runtime_exit (2);
      if ((t->flags & SigThrow) == 0)
	return;

      runtime_startpanic ();

      /* We should do a stack backtrace here.  Until we can do that,
	 we reraise the signal in order to get a slightly better
	 report from the shell.  */

      memset (&sa, 0, sizeof sa);

      sa.sa_handler = SIG_DFL;

      i = sigemptyset (&sa.sa_mask);
      __go_assert (i == 0);

      if (sigaction (sig, &sa, NULL) != 0)
	abort ();

      raise (sig);

      runtime_exit (2);
    }

  __builtin_unreachable ();
}
unsigned char *
mapiterinit (struct __go_map_type *mt, uintptr_t m)
{
  struct __go_hash_iter *it;

  __go_assert (mt->__common.__code == GO_MAP);
  it = __go_alloc (sizeof (struct __go_hash_iter));
  __go_mapiterinit ((struct __go_map *) m, it);
  return (unsigned char *) it;
}
Пример #19
0
void
__go_broadcast_to_select (struct __go_channel *channel)
{
    pthread_mutex_t *select_mutex;
    pthread_cond_t *select_cond;
    int i;

    select_mutex = channel->select_mutex;
    select_cond = channel->select_cond;

    i = pthread_mutex_unlock (&channel->lock);
    __go_assert (i == 0);

    __go_assert (select_mutex != NULL && select_cond != NULL);

    i = pthread_mutex_lock (select_mutex);
    __go_assert (i == 0);

    i = pthread_cond_broadcast (select_cond);
    __go_assert (i == 0);

    i = pthread_mutex_unlock (select_mutex);
    __go_assert (i == 0);

    i = pthread_mutex_lock (&channel->lock);
    __go_assert (i == 0);
}
Пример #20
0
_Bool
__go_synch_with_select (struct __go_channel *channel, _Bool is_send)
{
    struct __go_channel_select *p;
    int i;

    __go_assert (channel->num_entries == 0);

    i = pthread_mutex_lock (&__go_select_data_mutex);
    __go_assert (i == 0);

    for (p = (is_send
              ? channel->select_receive_queue
              : channel->select_send_queue);
            p != NULL;
            p = p->next)
    {
        if (*p->selected == NULL)
        {
            *p->selected = channel;
            *p->is_read = !is_send;
            if (is_send)
                channel->selected_for_receive = 1;
            else
                channel->selected_for_send = 1;
            break;
        }
    }

    i = pthread_mutex_unlock (&__go_select_data_mutex);
    __go_assert (i == 0);

    /* The caller is responsible for signalling the select condition
       variable so that the other select knows that something has
       changed.  We can't signal it here because we can't acquire the
       select mutex while we hold a channel lock.  */

    return p != NULL;
}
Пример #21
0
void
__initsig ()
{
  struct sigaction sa;
  int i;

  siginit ();

  memset (&sa, 0, sizeof sa);

  sa.sa_handler = sighandler;

  i = sigfillset (&sa.sa_mask);
  __go_assert (i == 0);

  for (i = 0; signals[i].sig != -1; ++i)
    {
      sa.sa_flags = signals[i].restart ? SA_RESTART : 0;
      if (sigaction (signals[i].sig, &sa, NULL) != 0)
	__go_assert (0);
    }
}
Пример #22
0
void
runtime_resetcpuprofiler(int32 hz)
{
  struct itimerval it;
  struct sigaction sa;
  int i;

  memset (&it, 0, sizeof it);

  memset (&sa, 0, sizeof sa);
  i = sigfillset (&sa.sa_mask);
  __go_assert (i == 0);

  if (hz == 0)
    {
      i = setitimer (ITIMER_PROF, &it, NULL);
      __go_assert (i == 0);

      sa.sa_handler = SIG_IGN;
      i = sigaction (SIGPROF, &sa, NULL);
      __go_assert (i == 0);
    }
  else
    {
      sa.sa_handler = sighandler;
      sa.sa_flags = SA_RESTART;
      i = sigaction (SIGPROF, &sa, NULL);
      __go_assert (i == 0);

      it.it_interval.tv_sec = 0;
      it.it_interval.tv_usec = 1000000 / hz;
      it.it_value = it.it_interval;
      i = setitimer (ITIMER_PROF, &it, NULL);
      __go_assert (i == 0);
    }

  m->profilehz = hz;
}
Пример #23
0
void
__go_unlock_and_notify_selects (struct __go_channel *channel)
{
    pthread_mutex_t* select_mutex;
    pthread_cond_t* select_cond;
    int i;

    select_mutex = channel->select_mutex;
    select_cond = channel->select_cond;

    i = pthread_mutex_unlock (&channel->lock);
    __go_assert (i == 0);

    if (select_mutex != NULL)
    {
        i = pthread_mutex_lock (select_mutex);
        __go_assert (i == 0);
        i = pthread_cond_broadcast (select_cond);
        __go_assert (i == 0);
        i = pthread_mutex_unlock (select_mutex);
        __go_assert (i == 0);
    }
}
Пример #24
0
static _Bool
is_queue_ready (struct __go_channel_select *queue)
{
  int x;

  if (queue == NULL)
    return 0;

  x = pthread_mutex_lock (&__go_select_data_mutex);
  __go_assert (x == 0);

  while (queue != NULL)
    {
      if (*queue->selected == NULL)
	break;
      queue = queue->next;
    }

  x = pthread_mutex_unlock (&__go_select_data_mutex);
  __go_assert (x == 0);

  return queue != NULL;
}
Пример #25
0
void
__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
{
  if (channel == NULL)
    __go_panic_msg ("send to nil channel");

  __go_assert (channel->element_size <= sizeof (uint64_t));

  __go_send_acquire (channel, for_select);

  channel->data[channel->next_store] = val;

  __go_send_release (channel);
}
void
__go_mapiter1 (struct __go_hash_iter *it, unsigned char *key)
{
  const struct __go_map *map;
  const struct __go_map_descriptor *descriptor;
  const struct __go_type_descriptor *key_descriptor;
  const char *p;

  map = it->map;
  descriptor = map->__descriptor;
  key_descriptor = descriptor->__map_descriptor->__key_type;
  p = it->entry;
  __go_assert (p != NULL);
  __builtin_memcpy (key, p + descriptor->__key_offset, key_descriptor->__size);
}
void
runtime_semacquire (uint32 *addr)
{
    while (1)
    {
        int i;

        /* If the current count is positive, and we are able to atomically
        decrement it, then we have acquired the semaphore.  */
        if (acquire (addr))
            return;

        /* Lock the mutex.  */
        i = pthread_mutex_lock (&sem_lock);
        __go_assert (i == 0);

        /* Check the count again with the mutex locked.  */
        if (acquire (addr))
        {
            i = pthread_mutex_unlock (&sem_lock);
            __go_assert (i == 0);
            return;
        }

        /* The count is zero.  Even if a call to runtime.Semrelease
        increments it to become positive, that call will try to
         acquire the mutex and block, so we are sure to see the signal
         of the condition variable.  */
        i = pthread_cond_wait (&sem_cond, &sem_lock);
        __go_assert (i == 0);

        /* Unlock the mutex and try again.  */
        i = pthread_mutex_unlock (&sem_lock);
        __go_assert (i == 0);
    }
}
struct mapaccess_ret
mapaccess (struct __go_map_type *mt, uintptr_t m, uintptr_t key_i)
{
  struct __go_map *map = (struct __go_map *) m;
  void *key;
  const struct __go_type_descriptor *key_descriptor;
  void *p;
  const struct __go_type_descriptor *val_descriptor;
  struct mapaccess_ret ret;
  void *val;
  void *pv;

  __go_assert (mt->__common.__code == GO_MAP);

  key_descriptor = mt->__key_type;
  if (__go_is_pointer_type (key_descriptor))
    key = &key_i;
  else
    key = (void *) key_i;

  if (map == NULL)
    p = NULL;
  else
    p = __go_map_index (map, key, 0);

  val_descriptor = mt->__val_type;
  if (__go_is_pointer_type (val_descriptor))
    {
      val = NULL;
      pv = &val;
    }
  else
    {
      val = __go_alloc (val_descriptor->__size);
      pv = val;
    }

  if (p == NULL)
    ret.pres = 0;
  else
    {
      __builtin_memcpy (pv, p, val_descriptor->__size);
      ret.pres = 1;
    }

  ret.val = (uintptr_t) val;
  return ret;
}
_Bool
__go_send_nonblocking_small (struct __go_channel *channel, uint64_t val)
{
  if (channel == NULL)
    return 0;

  __go_assert (channel->element_type->__size <= sizeof (uint64_t));

  if (!__go_send_nonblocking_acquire (channel))
    return 0;

  channel->data[channel->next_store] = val;

  __go_send_release (channel);

  return 1;
}
void
__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
{
  if (channel == NULL)
    {
      // Block forever.
      __go_select (0, 0, NULL, NULL);
    }

  __go_assert (channel->element_type->__size <= sizeof (uint64_t));

  __go_send_acquire (channel, for_select);

  channel->data[channel->next_store] = val;

  __go_send_release (channel);
}