/*
- PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002 - 2009 PowerDNS.COM BV
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation
-
- Additionally, the license of this program contains a special
- exception which allows to distribute the program in binary form when
- it is linked against OpenSSL.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <iostream>
+#ifdef PDNS_USE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif /* PDNS_USE_VALGRIND */
/** \page MTasker
Simple system for implementing cooperative multitasking of functions, with
which is passed to MTasker::makeThread(), together with a possible argument.
This function is now free to do whatever it wants, but realise that MTasker implements cooperative
- multitasking, which means that the coder has the responsiblilty of not taking the CPU overly long.
+ multitasking, which means that the coder has the responsibility of not taking the CPU overly long.
Other threads can only get the CPU if MTasker::yield() is called or if a thread sleeps to wait for an event,
using the MTasker::waitEvent() method.
unsigned int diff=d_threads[d_tid].dt.ndiff()/1000;
d_threads[d_tid].totTime+=diff;
#endif
+ notifyStackSwitchToKernel();
pdns_swapcontext(*d_waiters.find(key)->context,d_kernel); // 'A' will return here when 'key' has arrived, hands over control to kernel first
+ notifyStackSwitchDone();
#ifdef MTASKERTIMING
d_threads[d_tid].dt.start();
#endif
template<class Key, class Val>void MTasker<Key,Val>::yield()
{
d_runQueue.push(d_tid);
+ notifyStackSwitchToKernel();
pdns_swapcontext(*d_threads[d_tid].context ,d_kernel); // give control to the kernel
+ notifyStackSwitchDone();
}
//! reports that an event took place for which threads may be waiting
d_tid=waiter->tid; // set tid
d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for
auto userspace=std::move(waiter->context);
- d_waiters.erase(waiter); // removes the waitpoint
+ d_waiters.erase(waiter); // removes the waitpoint
+ notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize);
pdns_swapcontext(d_kernel,*userspace); // swaps back to the above point 'A'
+ notifyStackSwitchDone();
return 1;
}
auto uc=std::make_shared<pdns_ucontext_t>();
uc->uc_link = &d_kernel; // come back to kernel after dying
- uc->uc_stack.resize (d_stacksize);
+ uc->uc_stack.resize (d_stacksize+1);
+#ifdef PDNS_USE_VALGRIND
+ uc->valgrind_id = VALGRIND_STACK_REGISTER(&uc->uc_stack[0],
+ &uc->uc_stack[uc->uc_stack.size()-1]);
+#endif /* PDNS_USE_VALGRIND */
auto& thread = d_threads[d_maxtid];
auto mt = this;
#ifdef MTASKERTIMING
d_threads[d_tid].dt.start();
#endif
+ notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize);
pdns_swapcontext(d_kernel, *d_threads[d_tid].context);
-
+ notifyStackSwitchDone();
+
d_runQueue.pop();
return true;
}
d_eventkey=i->key; // pass waitEvent the exact key it was woken for
auto uc = i->context;
d_tid = i->tid;
- ttdindex.erase(i++); // removes the waitpoint
+ ttdindex.erase(i++); // removes the waitpoint
+ notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize);
pdns_swapcontext(d_kernel, *uc); // swaps back to the above point 'A'
+ notifyStackSwitchDone();
}
else if(i->ttd.tv_sec)
break;
+ else
+ ++i;
}
}
return false;
/** Call this to check if no processes are running anymore
\return true if no processes are left
*/
-template<class Key, class Val>bool MTasker<Key,Val>::noProcesses()
+template<class Key, class Val>bool MTasker<Key,Val>::noProcesses() const
{
return d_threads.empty();
}
/** Call this to perhaps limit activities if too many threads are running
\return number of processes running
*/
-template<class Key, class Val>unsigned int MTasker<Key,Val>::numProcesses()
+template<class Key, class Val>unsigned int MTasker<Key,Val>::numProcesses() const
{
return d_threads.size();
}
/** Processes can call this to get a numerical representation of their current thread ID.
This can be useful for logging purposes.
*/
-template<class Key, class Val>int MTasker<Key,Val>::getTid()
+template<class Key, class Val>int MTasker<Key,Val>::getTid() const
{
return d_tid;
}