void setenv_c (String k, String v) { const byte *ks; unsigned char *kn; const byte *vs; unsigned char *vn; ks = k.str; if (ks == NULL) ks = (const byte *) ""; kn = NULL; vs = v.str; if (vs == NULL) vs = (const byte *) ""; vn = NULL; #ifdef HAVE_SETENV if (ks != NULL && ks[k.len] != 0) { kn = __go_alloc (k.len + 1); __builtin_memcpy (kn, ks, k.len); ks = kn; } if (vs != NULL && vs[v.len] != 0) { vn = __go_alloc (v.len + 1); __builtin_memcpy (vn, vs, v.len); vs = vn; } setenv ((const char *) ks, (const char *) vs, 1); #else /* !defined(HAVE_SETENV) */ kn = __go_alloc (k.len + v.len + 2); __builtin_memcpy (kn, ks, k.len); kn[k.len] = '='; __builtin_memcpy (kn + k.len + 1, vs, v.len); kn[k.len + v.len + 1] = '\0'; putenv ((char *) kn); #endif /* !defined(HAVE_SETENV) */ if (kn != NULL) __go_free (kn); if (vn != NULL) __go_free (vn); }
void unsetenv_c (String k) { const byte *ks; unsigned char *kn; ks = k.str; if (ks == NULL) ks = (const byte *) ""; kn = NULL; #ifdef HAVE_UNSETENV intgo len; if (ks != NULL && ks[k.len] != 0) { // Objects that are explicitly freed must be at least 16 bytes in size, // so that they are not allocated using tiny alloc. len = k.len + 1; if (len < TinySize) len = TinySize; kn = __go_alloc (len); __builtin_memcpy (kn, ks, k.len); ks = kn; } unsetenv ((const char *) ks); #endif /* !defined(HAVE_UNSETENV) */ if (kn != NULL) __go_free (kn); }
void __go_undefer (_Bool *frame) { G *g; g = runtime_g (); while (g->defer != NULL && g->defer->__frame == frame) { struct __go_defer_stack *d; void (*pfn) (void *); d = g->defer; pfn = d->__pfn; d->__pfn = NULL; if (pfn != NULL) (*pfn) (d->__arg); g->defer = d->__next; __go_free (d); /* Since we are executing a defer function here, we know we are returning from the calling function. If the calling function, or one of its callees, paniced, then the defer functions would be executed by __go_panic. */ *frame = 1; } }
static void __go_map_rehash (struct __go_map *map) { const struct __go_map_descriptor *descriptor; const struct __go_type_descriptor *key_descriptor; uintptr_t key_offset; size_t key_size; size_t (*hashfn) (const void *, size_t); uintptr_t old_bucket_count; void **old_buckets; uintptr_t new_bucket_count; void **new_buckets; uintptr_t i; descriptor = map->__descriptor; key_descriptor = descriptor->__map_descriptor->__key_type; key_offset = descriptor->__key_offset; key_size = key_descriptor->__size; hashfn = key_descriptor->__hashfn; old_bucket_count = map->__bucket_count; old_buckets = map->__buckets; new_bucket_count = __go_map_next_prime (old_bucket_count * 2); new_buckets = (void **) __go_alloc (new_bucket_count * sizeof (void *)); __builtin_memset (new_buckets, 0, new_bucket_count * sizeof (void *)); for (i = 0; i < old_bucket_count; ++i) { char* entry; char* next; for (entry = old_buckets[i]; entry != NULL; entry = next) { size_t key_hash; size_t new_bucket_index; /* We could speed up rehashing at the cost of memory space by caching the hash code. */ key_hash = hashfn (entry + key_offset, key_size); new_bucket_index = key_hash % new_bucket_count; next = *(char **) entry; *(char **) entry = new_buckets[new_bucket_index]; new_buckets[new_bucket_index] = entry; } } __go_free (old_buckets); map->__bucket_count = new_bucket_count; map->__buckets = new_buckets; }
void __go_map_delete (struct __go_map *map, const void *key) { 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; void **pentry; if (map == NULL) runtime_panicstring ("deletion of entry in nil map"); 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; pentry = map->__buckets + bucket_index; while (*pentry != NULL) { char *entry = (char *) *pentry; if (equalfn (key, entry + key_offset, key_size)) { *pentry = *(void **) entry; __go_free (entry); map->__element_count -= 1; break; } pentry = (void **) entry; } }
void __go_undefer (_Bool *frame) { G *g; g = runtime_g (); while (g->defer != NULL && g->defer->__frame == frame) { struct __go_defer_stack *d; void (*pfn) (void *); M *m; d = g->defer; pfn = d->__pfn; d->__pfn = NULL; if (pfn != NULL) (*pfn) (d->__arg); g->defer = d->__next; /* This may be called by a cgo callback routine to defer the call to syscall.CgocallBackDone, in which case we will not have a memory context. Don't try to free anything in that case--the GC will release it later. */ m = runtime_m (); if (m != NULL && m->mcache != NULL && d->__free) __go_free (d); /* Since we are executing a defer function here, we know we are returning from the calling function. If the calling function, or one of its callees, paniced, then the defer functions would be executed by __go_panic. */ *frame = 1; } }
void __go_panic (struct __go_empty_interface arg) { G *g; Panic *n; g = runtime_g (); n = (Panic *) __go_alloc (sizeof (Panic)); n->arg = arg; n->next = g->_panic; g->_panic = n; /* Run all the defer functions. */ while (1) { Defer *d; void (*pfn) (void *); d = g->_defer; if (d == NULL) break; pfn = (void (*) (void *)) d->pfn; d->pfn = 0; if (pfn != NULL) { (*pfn) (d->arg); if (n->recovered) { /* Some defer function called recover. That means that we should stop running this panic. */ g->_panic = n->next; __go_free (n); /* Now unwind the stack by throwing an exception. The compiler has arranged to create exception handlers in each function which uses a defer statement. These exception handlers will check whether the entry on the top of the defer stack is from the current function. If it is, we have unwound the stack far enough. */ __go_unwind_stack (); /* __go_unwind_stack should not return. */ abort (); } /* Because we executed that defer function by a panic, and it did not call recover, we know that we are not returning from the calling function--we are panicing through it. */ *d->frame = 0; } g->_defer = d->next; /* This may be called by a cgo callback routine to defer the call to syscall.CgocallBackDone, in which case we will not have a memory context. Don't try to free anything in that case--the GC will release it later. */ if (runtime_m () != NULL) runtime_freedefer (d); } /* The panic was not recovered. */ runtime_startpanic (); __printpanics (g->_panic); runtime_dopanic (0); }
void __go_check_defer (_Bool *frame) { G *g; struct _Unwind_Exception *hdr; g = runtime_g (); if (g == NULL) { /* Some other language has thrown an exception. We know there are no defer handlers, so there is nothing to do. */ } else if (g->isforeign) { Panic *n; _Bool recovered; /* Some other language has thrown an exception. We need to run the local defer handlers. If they call recover, we stop unwinding the stack here. */ n = (Panic *) __go_alloc (sizeof (Panic)); n->arg.__type_descriptor = NULL; n->arg.__object = NULL; n->recovered = 0; n->isforeign = 1; n->next = g->_panic; g->_panic = n; while (1) { Defer *d; void (*pfn) (void *); d = g->_defer; if (d == NULL || d->frame != frame || d->pfn == 0) break; pfn = (void (*) (void *)) d->pfn; g->_defer = d->next; (*pfn) (d->arg); if (runtime_m () != NULL) runtime_freedefer (d); if (n->recovered) { /* The recover function caught the panic thrown by some other language. */ break; } } recovered = n->recovered; g->_panic = n->next; __go_free (n); if (recovered) { /* Just return and continue executing Go code. */ *frame = 1; return; } /* We are panicing through this function. */ *frame = 0; } else if (g->_defer != NULL && g->_defer->pfn == 0 && g->_defer->frame == frame) { Defer *d; /* This is the defer function which called recover. Simply return to stop the stack unwind, and let the Go code continue to execute. */ d = g->_defer; g->_defer = d->next; if (runtime_m () != NULL) runtime_freedefer (d); /* We are returning from this function. */ *frame = 1; return; } /* This is some other defer function. It was already run by the call to panic, or just above. Rethrow the exception. */ hdr = (struct _Unwind_Exception *) g->exception; #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_Resume_or_Rethrow (hdr); #else #if defined(_LIBUNWIND_STD_ABI) _Unwind_RaiseException (hdr); #else _Unwind_Resume_or_Rethrow (hdr); #endif #endif /* Rethrowing the exception should not return. */ abort(); }
void __go_panic (struct __go_empty_interface arg) { struct __go_panic_stack *n; if (__go_panic_defer == NULL) __go_panic_defer = ((struct __go_panic_defer_struct *) __go_alloc (sizeof (struct __go_panic_defer_struct))); n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack)); n->__arg = arg; n->__next = __go_panic_defer->__panic; __go_panic_defer->__panic = n; /* Run all the defer functions. */ while (1) { struct __go_defer_stack *d; void (*pfn) (void *); d = __go_panic_defer->__defer; if (d == NULL) break; pfn = d->__pfn; d->__pfn = NULL; if (pfn != NULL) { (*pfn) (d->__arg); if (n->__was_recovered) { /* Some defer function called recover. That means that we should stop running this panic. */ __go_panic_defer->__panic = n->__next; __go_free (n); /* Now unwind the stack by throwing an exception. The compiler has arranged to create exception handlers in each function which uses a defer statement. These exception handlers will check whether the entry on the top of the defer stack is from the current function. If it is, we have unwound the stack far enough. */ __go_unwind_stack (); /* __go_unwind_stack should not return. */ abort (); } } __go_panic_defer->__defer = d->__next; __go_free (d); } /* The panic was not recovered. */ __printpanics (__go_panic_defer->__panic); /* FIXME: We should dump a call stack here. */ abort (); }