From df1262e4bb33b78f429baec77e2c68e4d6c9d592 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Fri, 20 Apr 2007 10:06:52 +0000 Subject: [PATCH] Started work on select thread system. --- src/.cvsignore | 4 +- src/Makefile.am | 10 +-- src/sel_thread.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ src/sel_thread.h | 73 ++++++++++++++++++++ src/test_sel_thread.c | 67 +++++++++++++++++++ 5 files changed, 325 insertions(+), 5 deletions(-) create mode 100644 src/sel_thread.c create mode 100644 src/sel_thread.h create mode 100644 src/test_sel_thread.c diff --git a/src/.cvsignore b/src/.cvsignore index 589c1fe..fb93fcd 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -5,6 +5,8 @@ Makefile.in cconfig.h cconfig.h.in .deps +*.log stamp-h1 +test_config test_relevance -test_relevance.log +test_sel_thread diff --git a/src/Makefile.am b/src/Makefile.am index f006545..986317f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ -# $Id: Makefile.am,v 1.9 2007-04-19 19:42:30 marc Exp $ +# $Id: Makefile.am,v 1.10 2007-04-20 10:06:52 adam Exp $ bin_PROGRAMS = pazpar2 -check_PROGRAMS = test_config test_relevance +check_PROGRAMS = test_config test_relevance test_sel_thread TESTS = $(check_PROGRAMS) noinst_LIBRARIES = libpazpar2.a @@ -15,8 +15,7 @@ libpazpar2_a_SOURCES = config.c config.h eventl.c eventl.h \ logic.c pazpar2.h reclists.c reclists.h \ relevance.c relevance.h termlists.c termlists.h \ util.c util.h zeerex.c zeerex.h database.c database.h \ - settings.h settings.c - + settings.h settings.c sel_thread.c sel_thread.h pazpar2_SOURCES = pazpar2.c pazpar2_LDADD = libpazpar2.a $(YAZLIB) @@ -27,3 +26,6 @@ test_config_LDADD = libpazpar2.a $(YAZLIB) test_relevance_SOURCES = test_relevance.c test_relevance_LDADD = libpazpar2.a $(YAZLIB) +test_sel_thread_SOURCES = test_sel_thread.c +test_sel_thread_LDADD = libpazpar2.a $(YAZLIB) + diff --git a/src/sel_thread.c b/src/sel_thread.c new file mode 100644 index 0000000..7bd62dc --- /dev/null +++ b/src/sel_thread.c @@ -0,0 +1,176 @@ +/* $Id: sel_thread.c,v 1.1 2007-04-20 10:06:52 adam Exp $ + Copyright (c) 2006-2007, Index Data. + +This file is part of Pazpar2. + +Pazpar2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pazpar2; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#if HAVE_CONFIG_H +#include "cconfig.h" +#endif + +#include "sel_thread.h" +#include +#include +#include +#include +#include + +struct work_item { + void *data; + struct work_item *next; +}; + +struct sel_thread { + int fd[2]; + NMEM nmem; + pthread_t thread_id; + pthread_mutex_t mutex; + pthread_cond_t input_data; + int stop_flag; + struct work_item *input_queue; + struct work_item *output_queue; + struct work_item *free_queue; + void (*work_handler)(void *work_data);; +}; + +static void *sel_thread_handler(void *vp) +{ + sel_thread_t p = (sel_thread_t) vp; + + while(1) + { + struct work_item **work_p, *work_this; + /* wait for some work */ + pthread_mutex_lock(&p->mutex); + while (!p->stop_flag && !p->input_queue) + pthread_cond_wait(&p->input_data, &p->mutex); + /* see if we were waken up because we're shutting down */ + if (p->stop_flag) + break; + /* got something. Take the last one out of input_queue */ + work_p = &p->input_queue; + while ((*work_p)->next) + work_p = &(*work_p)->next; + work_this = *work_p; + *work_p = 0; + pthread_mutex_unlock(&p->mutex); + + /* work on this item */ + p->work_handler(work_this->data); + + /* put it back into output queue */ + pthread_mutex_lock(&p->mutex); + work_this->next = p->output_queue; + p->output_queue = work_this; + pthread_mutex_unlock(&p->mutex); + + /* wake up select/poll with a single byte */ + write(p->fd[1], "", 1); + } + pthread_mutex_unlock(&p->mutex); + return 0; +} + +sel_thread_t sel_thread_create(void (*work_handler)(void *work_data), + int *read_fd) +{ + NMEM nmem = nmem_create(); + sel_thread_t p = nmem_malloc(nmem, sizeof(*p)); + + p->nmem = nmem; + if (pipe(p->fd)) + { + nmem_destroy(nmem); + return 0; + } + *read_fd = p->fd[0]; + p->input_queue = 0; + p->output_queue = 0; + p->free_queue = 0; + p->work_handler = work_handler; + + p->stop_flag = 0; + pthread_mutex_init(&p->mutex, 0); + pthread_cond_init(&p->input_data, 0); + pthread_create (&p->thread_id, 0, sel_thread_handler, p); + return p; +} + +void sel_thread_destroy(sel_thread_t p) +{ + pthread_mutex_lock(&p->mutex); + + p->stop_flag = 1; + pthread_cond_broadcast(&p->input_data); + pthread_mutex_unlock(&p->mutex); + + pthread_join(p->thread_id, 0); + + close(p->fd[0]); + close(p->fd[1]); + pthread_cond_destroy(&p->input_data); + pthread_mutex_destroy(&p->mutex); + nmem_destroy(p->nmem); +} + +void sel_thread_add(sel_thread_t p, void *data) +{ + struct work_item *work_p; + + pthread_mutex_lock(&p->mutex); + work_p = p->free_queue; + if (!work_p) + work_p = nmem_malloc(p->nmem, sizeof(*work_p)); + + work_p->data = data; + work_p->next = p->input_queue; + p->input_queue = work_p; + pthread_mutex_unlock(&p->mutex); +} + +void *sel_thread_result(sel_thread_t p) +{ + struct work_item **work_p, *work_this; + void *data; + + /* got something. Take the last one out of output_queue */ + work_p = &p->output_queue; + if (!*work_p) + return 0; + while ((*work_p)->next) + work_p = &(*work_p)->next; + work_this = *work_p; + *work_p = 0; + + /* put freed item in free list */ + work_this->next = p->free_queue; + p->free_queue = work_this; + + data = work_this->data; + pthread_mutex_unlock(&p->mutex); + + return data; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/sel_thread.h b/src/sel_thread.h new file mode 100644 index 0000000..dc7036b --- /dev/null +++ b/src/sel_thread.h @@ -0,0 +1,73 @@ +/* $Id: sel_thread.h,v 1.1 2007-04-20 10:06:52 adam Exp $ + Copyright (c) 2006-2007, Index Data. + +This file is part of Pazpar2. + +Pazpar2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pazpar2; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#ifndef SEL_THREAD_H +#define SEL_THREAD_H +#include + +YAZ_BEGIN_CDECL + +/** \brief select thread handler type */ +typedef struct sel_thread *sel_thread_t; + +/** \brief creates select thread + \param work_handler handler that does work in worker thread + \param read_fd pointer to readable socket upon completion + \returns select thread handler + + Creates a worker thread. The worker thread will signal "completed" + work by sending one byte to the read_fd file descriptor. + You are supposed to select or poll on that for reading and + call sel_thread_result accordingly. +*/ +sel_thread_t sel_thread_create(void (*work_handler)(void *work_data), + int *read_fd); + +/** \brief destorys select thread + \param p select thread handler +*/ +void sel_thread_destroy(sel_thread_t p); + +/** \brief adds work to be carried out in thread + \param p select thread handler + \param data pointer to data that work_handler knows about +*/ +void sel_thread_add(sel_thread_t p, void *data); + +/** \brief gets result of work + \param p select thread handler + \returns data for work (which work_handler has been working on) +*/ +void *sel_thread_result(sel_thread_t p); + +YAZ_END_CDECL + + +#endif + + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/test_sel_thread.c b/src/test_sel_thread.c new file mode 100644 index 0000000..6f77bf7 --- /dev/null +++ b/src/test_sel_thread.c @@ -0,0 +1,67 @@ +/* $Id: test_sel_thread.c,v 1.1 2007-04-20 10:06:52 adam Exp $ + Copyright (c) 2006-2007, Index Data. + +This file is part of Pazpar2. + +Pazpar2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pazpar2; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#if HAVE_CONFIG_H +#include "cconfig.h" +#endif + +#include "sel_thread.h" +#include + +struct my_work_data { + int x; +}; + +static void work_handler(void *vp) +{ + struct my_work_data *p = vp; + p->x += 2; +} + +static void test_1(void) +{ + int fd; + sel_thread_t p = sel_thread_create(work_handler, &fd); + YAZ_CHECK(p); + + sel_thread_destroy(p); +} + +int main(int argc, char **argv) +{ + YAZ_CHECK_INIT(argc, argv); + YAZ_CHECK_LOG(); + + test_1(); + + YAZ_CHECK_TERM; +} + + + + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ -- 1.7.10.4