+
+ /* This is safe without any locks held because, if the caller
+ * is able to request the Nth entry of the DTV, the DSO list
+ * must be valid at least that far out and it was synchronized
+ * at program startup or by an already-completed call to dlopen. */
+ struct dso *p;
+ for (p=head; p->tls_id != v[0]; p=p->next);
+
+ /* Get new DTV space from new DSO if needed */
+ if (!self->dtv || v[0] > (size_t)self->dtv[0]) {
+ void **newdtv = p->new_dtv +
+ (v[0]+1)*sizeof(void *)*a_fetch_add(&p->new_dtv_idx,1);
+ if (self->dtv) memcpy(newdtv, self->dtv,
+ ((size_t)self->dtv[0]+1) * sizeof(void *));
+ newdtv[0] = (void *)v[0];
+ self->dtv = newdtv;
+ }
+
+ /* Get new TLS memory from new DSO */
+ unsigned char *mem = p->new_tls +
+ (p->tls_size + p->tls_align) * a_fetch_add(&p->new_tls_idx,1);
+ mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) & (p->tls_align-1);
+ self->dtv[v[0]] = mem;
+ memcpy(mem, p->tls_image, p->tls_len);
+ pthread_sigmask(SIG_SETMASK, &set, 0);
+ return mem + v[1];
+}
+
+static void update_tls_size()
+{
+ libc.tls_size = ALIGN(
+ (1+tls_cnt) * sizeof(void *) +
+ tls_offset +
+ sizeof(struct pthread) +
+ tls_align * 2,
+ tls_align);