void thread_destroy(struct thread *t) { if (t != NULL) { thread_clear(t); vm_stack_destroy(t->vm_stack); free(t->ref_buckets); ref_set_destroy(t->excluded_set); #ifdef DMP if (t->dmp != NULL) thread_dmp_destroy(t->dmp); #endif heap_free(heap, t); free(t->free_buckets); } }
static struct replay_thread * thread_get(int fd, void *(*thread_main)(void *)) { assert(fd != 0); if (fd >= nthreads) { struct replay_thread **newthreads = threads; size_t newnthreads = nthreads; while (fd >= newnthreads) newnthreads += newnthreads + 1; newthreads = realloc(newthreads, newnthreads * sizeof *newthreads); XXXAN(newthreads != NULL); memset(newthreads + nthreads, 0, (newnthreads - nthreads) * sizeof *newthreads); threads = newthreads; nthreads = newnthreads; } if (threads[fd] == NULL) { threads[fd] = malloc(sizeof *threads[fd]); assert(threads[fd] != NULL); threads[fd]->sock = -1; thread_clear(threads[fd]); mailbox_create(&threads[fd]->mbox); if (pthread_create(&threads[fd]->thread_id, &thread_attr, thread_main, threads[fd]) != 0) { thread_log(0, errno, "pthread_create()"); mailbox_destroy(&threads[fd]->mbox); freez(threads[fd]); threads[fd] = THREAD_FAIL; } else { threads[fd]->fd = fd; thread_log(0, 0, "thread %p:%d started", (void *)threads[fd]->thread_id, fd); } } if (threads[fd] == THREAD_FAIL) return (NULL); return (threads[fd]); }
static void thread_close(int fd) { if (fd == -1) { for (fd = 0; fd < nthreads; ++fd) thread_close(fd); return; } assert(fd < nthreads); if (threads[fd] == NULL) return; mailbox_close(&threads[fd]->mbox); pthread_join(threads[fd]->thread_id, NULL); thread_log(0, 0, "thread %p stopped", (void *)threads[fd]->thread_id); thread_clear(threads[fd]); mailbox_destroy(&threads[fd]->mbox); freez(threads[fd]); }
static void * replay_thread(void *arg) { struct iovec iov[6]; char space[1] = " ", crlf[2] = "\r\n"; struct replay_thread *thr = arg; struct message *msg; enum shmlogtag tag; size_t len; char *ptr; const char *next; int i; int reopen = 1; while ((msg = mailbox_get(&thr->mbox)) != NULL) { tag = msg->tag; len = msg->len; ptr = msg->ptr; thread_log(2, 0, "%s(%s)", VSL_tags[tag], msg->ptr); switch (tag) { case SLT_RxRequest: if (thr->method != NULL) thr->bogus = 1; else thr->method = trimline(thr, ptr); break; case SLT_RxURL: if (thr->url != NULL) thr->bogus = 1; else thr->url = trimline(thr, ptr); break; case SLT_RxProtocol: if (thr->proto != NULL) thr->bogus = 1; else thr->proto = trimline(thr, ptr); break; case SLT_RxHeader: if (thr->nhdr >= sizeof thr->hdr / sizeof *thr->hdr) { thr->bogus = 1; } else { thr->hdr[thr->nhdr++] = trimline(thr, ptr); if (isprefix(ptr, "connection:", &next)) thr->conn = trimline(thr, next); } break; default: break; } freez(msg->ptr); freez(msg); if (tag != SLT_ReqEnd) continue; if (!thr->method || !thr->url || !thr->proto) { thr->bogus = 1; } else if (strcmp(thr->method, "GET") != 0 && strcmp(thr->method, "HEAD") != 0) { thr->bogus = 1; } else if (strcmp(thr->proto, "HTTP/1.0") == 0) { reopen = !(thr->conn && strcasecmp(thr->conn, "keep-alive") == 0); } else if (strcmp(thr->proto, "HTTP/1.1") == 0) { reopen = (thr->conn && strcasecmp(thr->conn, "close") == 0); } else { thr->bogus = 1; } if (thr->bogus) { thread_log(1, 0, "bogus"); goto clear; } if (thr->sock == -1) { for (;;) { thread_log(1, 0, "sleeping before connect..."); usleep(1000 * (thr->fd % 3001)); if ((thr->sock = VSS_connect(addr_info)) >= 0) break; thread_log(0, errno, "connect failed"); } } thread_log(1, 0, "%s %s %s", thr->method, thr->url, thr->proto); iov[0].iov_base = thr->method; iov[0].iov_len = strlen(thr->method); iov[2].iov_base = thr->url; iov[2].iov_len = strlen(thr->url); iov[4].iov_base = thr->proto; iov[4].iov_len = strlen(thr->proto); iov[1].iov_base = iov[3].iov_base = space; iov[1].iov_len = iov[3].iov_len = 1; iov[5].iov_base = crlf; iov[5].iov_len = 2; if (writev(thr->sock, iov, 6) == -1) { thread_log(0, errno, "writev()"); goto close; } for (i = 0; i < thr->nhdr; ++i) { thread_log(2, 0, "%d %s", i, thr->hdr[i]); iov[0].iov_base = thr->hdr[i]; iov[0].iov_len = strlen(thr->hdr[i]); iov[1].iov_base = crlf; iov[1].iov_len = 2; if (writev(thr->sock, iov, 2) == -1) { thread_log(0, errno, "writev()"); goto close; } } if (write(thr->sock, crlf, 2) == -1) { thread_log(0, errno, "writev()"); goto close; } if (receive_response(thr) || reopen) { close: thread_log(1, 0, "close"); assert(thr->sock != -1); close(thr->sock); thr->sock = -1; } sleep(1); clear: /* clean up */ thread_clear(thr); } /* leftovers */ thread_clear(thr); return (0); }