Skip to content

Instantly share code, notes, and snippets.

@jon
Created November 10, 2009 22:53
Show Gist options
  • Save jon/231346 to your computer and use it in GitHub Desktop.
Save jon/231346 to your computer and use it in GitHub Desktop.
void init_shm() {
shm_global_key = ftok(IPC_KEY_FILE, SHM_GLOBAL_KEY);
shm_thread_key = ftok(IPC_KEY_FILE, SHM_THREAD_KEY);
if ((shm_global_d = shmget(shm_global_key, sizeof(shm_global_t),
IPC_CREAT | 0660)) < 0) {
perror("shmget-global");
return 5;
}
if ((shm_thread_d = shmget(shm_thread_key,
sizeof(shm_thread_t) * num_threads,
IPC_CREAT | 0660)) < 0) {
perror("shmget-thread");
return 6;
}
shm_global = shmat(shm_global_d, NULL, 0);
shm_thread = shmat(shm_thread_d, NULL, 0);
if (-1 == (int) shm_global || -1 == (int) shm_thread) {
perror("shmat");
return 7;
}
memset(shm_global, 0, sizeof(shm_global_t));
memset(shm_thread, 0, sizeof(shm_thread_t) * num_threads);
pthread_mutex_init(&shm_global->request_mutex, NULL);
pthread_cond_init(&shm_global->request, NULL);
pthread_mutex_init(&shm_global->segment_id_mutex, NULL);
pthread_cond_init(&shm_global->ready, NULL);
shm_global->requests_pending = 0;
shm_global->segment_id = 0;
shm_global->segment_count = num_threads;
pthread_attr_init(&pthread_attrs);
pthread_attr_setdetachstate(&pthread_attrs, PTHREAD_CREATE_DETACHED);
for (i = 0; i < num_threads; ++i) {
pthread_mutex_init(&shm_thread[i].mutex, NULL);
pthread_cond_init(&shm_thread[i].cond, NULL);
pthread_create(&thread_id, &pthread_attrs, worker_routine, (void *) i);
}
pthread_create(&thread_id, &pthread_attrs, shmem_routine, NULL);
}
void *shmem_routine(void *nothing) {
while (1) {
pthread_mutex_lock(&shm_global->request_mutex);
pthread_cond_wait(&shm_global->request, &shm_global->request_mutex);
printf("Checking pending\n");
for (; shm_global->requests_pending > 0; shm_global->requests_pending--) {
printf("Enqueuing request...\n");
enqueue(&socket_queue, USE_SHMEM, 0);
}
pthread_mutex_unlock(&shm_global->request_mutex);
}
}
static void service_local_request(FILE *stream, char *path)
{
int segment_id;
shm_thread_t *srv_thread;
printf("Entering service_local_request\n");
pthread_mutex_lock(&server_shm->request_mutex);
server_shm->requests_pending++;
pthread_cond_signal(&server_shm->request);
pthread_mutex_lock(&server_shm->segment_id_mutex);
pthread_mutex_unlock(&server_shm->request_mutex);
pthread_cond_wait(&server_shm->ready, &server_shm->segment_id_mutex);
/* Server thread segment id is in server_shm */
segment_id = server_shm->segment_id;
printf("Got segment_id: %d\n", segment_id);
fflush(stdout);
srv_thread = &server_threads_shm[segment_id];
pthread_mutex_unlock(&server_shm->segment_id_mutex);
pthread_mutex_lock(&srv_thread->mutex);
strncpy(srv_thread->data, path, 512 * 1024);
srv_thread->data_size = strlen(path) > 512 * 1024 ? 512 * 1024 : strlen(path);
pthread_cond_signal(&srv_thread->cond);
pthread_cond_wait(&srv_thread->cond, &srv_thread->mutex);
do {
if (srv_thread->data_size > 0) {
fwrite(srv_thread->data, srv_thread->data_size, 1, stream);
fflush(stream);
}
pthread_cond_signal(&srv_thread->cond);
pthread_cond_wait(&srv_thread->cond, &srv_thread->mutex);
} while (!srv_thread->done);
pthread_cond_signal(&srv_thread->cond);
pthread_mutex_unlock(&srv_thread->mutex);
}
static void service_shm(int segment_id) {
char *file;
char *response;
int fd, len;
struct stat sb;
shm_thread_t *shm = &shm_thread[segment_id];
pthread_cond_wait(&shm->cond, &shm->mutex);
file = strdup(&shm->data[1]);
strdecode(file, file);
if (file[0] == '\0')
file = "./";
len = strlen(file);
if (file[0] == '/' || strcmp(file, "..") == 0 || strncmp(file, "../", 3) == 0 || strstr(file, "/../") != (char *) 0 || strcmp(&(file[len - 3]), "/..") == 0) {
free(file);
response = make_error(400, "Bad Request", (char *) 0, "Illegal filename.");
write_shm(segment_id, response, strlen(response));
free(response);
close_shm(segment_id);
return;
}
if (stat(file, &sb) < 0) {
free(file);
response = make_error(404, "Not Found", (char *) 0, "File not found.");
write_shm(segment_id, response, strlen(response));
free(response);
close_shm(segment_id);
return;
}
fd = open(file, O_RDONLY, 0);
if (fd < 0) {
free(file);
response = make_error(403, "Forbidden", (char *) 0, "File is protected.");
write_shm(segment_id, response, strlen(response));
free(response);
close_shm(segment_id);
return;
}
free(file);
response = make_headers(200, "Ok", (char *) 0, get_mime_type(file), sb.st_size, sb.st_mtime);
write_shm(segment_id, response, strlen(response));
free(response);
do {
len = read(fd, shm->data, SHM_BUF_SIZE);
shm->data_size = len;
pthread_cond_signal(&shm->cond);
pthread_cond_wait(&shm->cond, &shm->mutex);
} while (len > 0);
close(fd);
close_shm(segment_id);
}
static void write_shm(int segment_id, char *data, int len) {
shm_thread_t *shm = &shm_thread[segment_id];
shm->data_size = len < SHM_BUF_SIZE ? len : SHM_BUF_SIZE;
memcpy(shm->data, data, shm->data_size);
pthread_cond_signal(&shm->cond);
pthread_cond_wait(&shm->cond, &shm->mutex);
}
static void close_shm(int segment_id) {
shm_thread_t *shm = &shm_thread[segment_id];
shm->data_size = 0;
shm->done = 1;
pthread_cond_signal(&shm->cond);
pthread_cond_wait(&shm->cond, &shm->mutex);
}
/****************************************************************************/
/** Kevin Webb gtg247r **/
/** Jon Olson gtg620b **/
/****************************************************************************/
#ifndef _SHMEM_STUFF_H
#define _SHMEM_STUFF_H
#define IPC_KEY_FILE "/"
#define SHM_GLOBAL_KEY 0xf00d
#define SHM_THREAD_KEY 0xf00f
#define SHM_BUF_SIZE 512 * 1024
#include <pthread.h>
typedef struct {
pthread_mutex_t request_mutex;
pthread_cond_t request;
pthread_mutex_t segment_id_mutex;
pthread_cond_t ready;
int requests_pending;
int segment_id;
int segment_count;
} shm_global_t;
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int done;
size_t data_size;
char data[SHM_BUF_SIZE];
} shm_thread_t;
#endif /* _SHMEM_STUFF_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment