1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 2010-2011, 2013 Licq developers <licq-dev@googlegroups.com>
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #ifndef LICQDAEMON_PLUGINTHREAD_H
21 #define LICQDAEMON_PLUGINTHREAD_H
22 
23 #include "utils/dynamiclibrary.h"
24 
25 #include <boost/noncopyable.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <pthread.h>
28 
29 namespace LicqDaemon
30 {
31 
32 /**
33  * The PluginThread class starts a new thread and loads, initializes and starts
34  * the plugin in that thread. By loading the plugin in the same thread as it is
35  * later run in we hope to avoid problems with libraries' initialization
36  * routines not being run in the "main" thread.
37  */
38 class PluginThread : private boost::noncopyable
39 {
40 public:
41   typedef boost::shared_ptr<PluginThread> Ptr;
42 
43   struct Data;
44 
45   /**
46    * Create a new PluginThread instance, but without starting a new thread for
47    * it. Instead make it use the current thread (i.e. the caller's thread). The
48    * caller's execution will continue in a new thread with the entry point
49    * given in @a newThreadEntry. The argument to @a newThreadEntry will be the
50    * newly created PluginThread instance.
51    */
52   static int createWithCurrentThread(int (*newThreadEntry)(PluginThread::Ptr));
53 
54   PluginThread();
55   ~PluginThread();
56 
57   /**
58    * Stop thread if startPlugin() hasn't been called. Mostly for unit test.
59    */
60   void stop();
61 
62   /**
63    * Wait for the thread to exit.
64    * @return The thread's exit value. If the thread has been canceled, the
65    * return value is PTHREAD_CANCELED.
66    */
67   void* join();
68 
69   void cancel();
70   bool isThread(const pthread_t& thread) const;
71 
72   DynamicLibrary::Ptr loadPlugin(const std::string& path);
73   void createPlugin(void (*pluginCreate)(void*), void* argument);
74   bool initPlugin(bool (*pluginInit)(void*), void* argument);
75   void startPlugin(void* (*pluginStart)(void*), void* argument);
76 
77 private:
78   explicit PluginThread(bool);
79   void waitForThreadToStart();
80 
81   struct NewThreadData;
82   static void* newThreadEntry(void* data);
83 
84   const bool myIsThreadOwner;
85   pthread_t myThread;
86   Data* myData;
87   void* myExitValue;
88 };
89 
90 } // namespace LicqDaemon
91 
92 #endif
93