summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2018-04-23 17:25:10 +0300
committerGeorge Hazan <ghazan@miranda.im>2018-04-23 17:25:10 +0300
commit389fa94f1b09f0b1e97d2ecc11c994a12801b898 (patch)
tree5743c2ecf7ee3376407a5d1991d2f039bab00d62 /src
parentc475a38756f0f7a0404b62e6c4f924ca9900b25a (diff)
pack of fixes for complete dynamic reload of protocols
fixes #1295
Diffstat (limited to 'src')
-rw-r--r--src/mir_app/src/miranda.h14
-rw-r--r--src/mir_app/src/options.cpp17
-rw-r--r--src/mir_app/src/pluginopts.cpp7
-rw-r--r--src/mir_app/src/proto_accs.cpp39
-rw-r--r--src/mir_app/src/proto_opts.cpp8
-rw-r--r--src/mir_core/src/threads.cpp61
6 files changed, 93 insertions, 53 deletions
diff --git a/src/mir_app/src/miranda.h b/src/mir_app/src/miranda.h
index ad3370ff48..e1674f4b06 100644
--- a/src/mir_app/src/miranda.h
+++ b/src/mir_app/src/miranda.h
@@ -66,6 +66,7 @@ void UninitIni(void);
extern HINSTANCE g_hInst;
extern DWORD hMainThreadId;
extern HANDLE hOkToExitEvent, hModulesLoadedEvent, hevLoadModule, hevUnloadModule;
+extern HANDLE hAccListChanged;
extern wchar_t mirandabootini[MAX_PATH];
extern struct pluginEntry *plugin_crshdmp, *plugin_service, *plugin_ssl, *plugin_clist;
extern bool bModulesLoadedFired;
@@ -163,10 +164,19 @@ int FreeDefaultAccount(PROTO_INTERFACE* ppi);
bool ActivateAccount(PROTOACCOUNT *pa, bool bIsDynamic);
void EraseAccount(const char *pszProtoName);
-void DeactivateAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase);
-void UnloadAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase);
void OpenAccountOptions(PROTOACCOUNT *pa);
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define DAF_DYNAMIC 0x0001
+#define DAF_ERASE 0x0002
+#define DAF_FORK 0x0004
+
+void DeactivateAccount(PROTOACCOUNT *pa, int flags);
+void UnloadAccount(PROTOACCOUNT *pa, int flags);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
void LoadDbAccounts(void);
void WriteDbAccounts(void);
diff --git a/src/mir_app/src/options.cpp b/src/mir_app/src/options.cpp
index c6780393f2..0cc0f87a49 100644
--- a/src/mir_app/src/options.cpp
+++ b/src/mir_app/src/options.cpp
@@ -371,10 +371,11 @@ class COptionsDlg : public CDlgBase
{
int m_currentPage;
HTREEITEM m_hCurrentPage;
- LIST<OptionsPageData> m_arOpd, m_arDeleted;
+ LIST<OptionsPageData> m_arOpd, m_arDeleted, m_arInserted;
RECT m_rcDisplay;
RECT m_rcTab;
HFONT m_hBoldFont;
+ bool m_bInsideApply = false;
wchar_t m_szFilterString[1024];
const wchar_t *m_szCaption, *m_szGroup, *m_szPage, *m_szTab;
@@ -693,6 +694,7 @@ public:
m_timerRebuild(this, NEW_PAGE_TIMER),
m_arOpd(10),
m_arDeleted(1),
+ m_arInserted(1),
m_szCaption(pszCaption),
m_szGroup(pszGroup),
m_szPage(pszPage),
@@ -838,6 +840,7 @@ public:
}
LIST<OptionsPageData> arChanged(10, CompareOPD);
+ m_bInsideApply = true;
PSHNOTIFY pshn = {};
pshn.hdr.code = PSN_APPLY;
@@ -859,10 +862,17 @@ public:
m_currentPage = m_arOpd.indexOf(&p);
if (opd)
opd->pDialog->Show();
+ m_bInsideApply = false;
return;
}
}
+ m_bInsideApply = false;
+ for (auto &it : m_arInserted)
+ m_arOpd.insert(it);
+ m_arInserted.destroy();
+
+ // send PSN_WIZFINISH once to last changed tab that belongs to the same group
pshn.hdr.code = PSN_WIZFINISH;
for (int i = 0; i < arChanged.getCount(); i++) {
OptionsPageData *p = arChanged[i];
@@ -1118,7 +1128,10 @@ public:
if (opd->pDialog == nullptr) // smth went wrong
delete opd;
else {
- m_arOpd.insert(opd);
+ if (m_bInsideApply)
+ m_arInserted.insert(opd);
+ else
+ m_arOpd.insert(opd);
m_timerRebuild.Start(50);
}
}
diff --git a/src/mir_app/src/pluginopts.cpp b/src/mir_app/src/pluginopts.cpp
index 8e75ac0eb4..0bddc0f6f4 100644
--- a/src/mir_app/src/pluginopts.cpp
+++ b/src/mir_app/src/pluginopts.cpp
@@ -189,9 +189,10 @@ static bool LoadPluginDynamically(PluginListItemData *dat)
if (pd->hInst != pPlug->bpi.hInst)
continue;
- for (auto &pa : accounts)
- if (pa->ppro == nullptr && !mir_strcmp(pa->szProtoName, pd->szName))
- ActivateAccount(pa, true);
+ for (auto &pa : accounts)
+ if (pa->ppro == nullptr && !mir_strcmp(pa->szProtoName, pd->szName) && pa->bIsEnabled)
+ if (ActivateAccount(pa, true))
+ NotifyEventHooks(hAccListChanged, PRAC_ADDED, (LPARAM)pa);
}
dat->hInst = pPlug->bpi.hInst;
diff --git a/src/mir_app/src/proto_accs.cpp b/src/mir_app/src/proto_accs.cpp
index 141f14c706..405d691f6e 100644
--- a/src/mir_app/src/proto_accs.cpp
+++ b/src/mir_app/src/proto_accs.cpp
@@ -332,7 +332,7 @@ struct DeactivationThreadParam
{
PROTO_INTERFACE *ppro;
pfnUninitProto fnUninit;
- bool bIsDynamic, bErase;
+ int flags;
};
pfnUninitProto GetProtocolDestructor(char *szProto);
@@ -344,7 +344,7 @@ static int DeactivationThread(DeactivationThreadParam* param)
char *szModuleName = NEWSTR_ALLOCA(p->m_szModuleName);
- if (param->bIsDynamic) {
+ if (param->flags & DAF_DYNAMIC) {
while (!p->IsReadyToExit())
SleepEx(100, TRUE);
@@ -354,7 +354,7 @@ static int DeactivationThread(DeactivationThreadParam* param)
KillObjectThreads(p); // waits for them before terminating
KillObjectEventHooks(p); // untie an object from the outside world
- if (param->bErase)
+ if (param->flags & DAF_ERASE)
p->OnErase();
if (param->fnUninit)
@@ -362,14 +362,14 @@ static int DeactivationThread(DeactivationThreadParam* param)
KillObjectServices(p);
- if (param->bErase)
+ if (param->flags & DAF_ERASE)
EraseAccount(szModuleName);
delete param;
return 0;
}
-void DeactivateAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase)
+void DeactivateAccount(PROTOACCOUNT *pa, int flags)
{
if (pa->hwndAccMgrUI) {
DestroyWindow(pa->hwndAccMgrUI);
@@ -377,10 +377,13 @@ void DeactivateAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase)
pa->bAccMgrUIChanged = FALSE;
}
- pa->iIconBase = -1;
+ if (flags & DAF_DYNAMIC)
+ pa->bDynDisabled = true;
+
+ NotifyEventHooks(hAccListChanged, PRAC_REMOVED, (LPARAM)pa);
if (pa->ppro == nullptr) {
- if (bErase)
+ if (flags & DAF_ERASE)
EraseAccount(pa->szModuleName);
return;
}
@@ -388,10 +391,9 @@ void DeactivateAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase)
DeactivationThreadParam *param = new DeactivationThreadParam;
param->ppro = pa->ppro;
param->fnUninit = GetProtocolDestructor(pa->szProtoName);
- param->bIsDynamic = bIsDynamic;
- param->bErase = bErase;
+ param->flags = flags;
pa->ppro = nullptr;
- if (bIsDynamic)
+ if (flags & DAF_FORK)
mir_forkthread((pThreadFunc)DeactivationThread, param);
else
DeactivationThread(param);
@@ -405,12 +407,9 @@ void KillModuleAccounts(HINSTANCE hInst)
if (pd->hInst != hInst)
continue;
- for (auto &pa : accounts.rev_iter()) {
- if (!mir_strcmp(pa->szProtoName, pd->szName)) {
- DeactivateAccount(pa, false, false);
- pa->bDynDisabled = true;
- }
- }
+ for (auto &pa : accounts.rev_iter())
+ if (!mir_strcmp(pa->szProtoName, pd->szName))
+ DeactivateAccount(pa, DAF_DYNAMIC);
}
}
@@ -431,9 +430,9 @@ void EraseAccount(const char *pszModuleName)
/////////////////////////////////////////////////////////////////////////////////////////
-void UnloadAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase)
+void UnloadAccount(PROTOACCOUNT *pa, int flags)
{
- DeactivateAccount(pa, bIsDynamic, bErase);
+ DeactivateAccount(pa, flags);
replaceStrW(pa->tszAccountName, 0);
replaceStr(pa->szProtoName, 0);
@@ -442,7 +441,7 @@ void UnloadAccount(PROTOACCOUNT *pa, bool bIsDynamic, bool bErase)
// szModuleName should be freed only on a program's exit.
// otherwise many plugins dependand on static protocol names will crash!
// do NOT fix this 'leak', please
- if (!bIsDynamic) {
+ if (!(flags & DAF_DYNAMIC)) {
mir_free(pa->szModuleName);
mir_free(pa);
}
@@ -454,7 +453,7 @@ void UnloadAccountsModule()
auto T = accounts.rev_iter();
for (auto &it : T) {
- UnloadAccount(it, false, false);
+ UnloadAccount(it, 0);
accounts.remove(T.indexOf(&it));
}
accounts.destroy();
diff --git a/src/mir_app/src/proto_opts.cpp b/src/mir_app/src/proto_opts.cpp
index a506e633ea..e8f76ad3f0 100644
--- a/src/mir_app/src/proto_opts.cpp
+++ b/src/mir_app/src/proto_opts.cpp
@@ -48,8 +48,6 @@ Alternatively, just click on the Plus sign underneath the list to set up a new I
static class CAccountManagerDlg *pAccMgr = nullptr;
-extern HANDLE hAccListChanged;
-
int UnloadPlugin(wchar_t* buf, int bufLen);
MIR_APP_DLL(PROTOACCOUNT*) Proto_CreateAccount(const char *pszInternal, const char *pszBaseProto, const wchar_t *tszAccountName)
@@ -462,7 +460,7 @@ public:
}
if (!pa->bIsEnabled)
- DeactivateAccount(pa, true, false);
+ DeactivateAccount(pa, DAF_DYNAMIC | DAF_FORK);
}
WriteDbAccounts();
@@ -554,7 +552,7 @@ public:
WriteDbAccounts();
NotifyEventHooks(hAccListChanged, PRAC_REMOVED, (LPARAM)pa);
- UnloadAccount(pa, true, true);
+ UnloadAccount(pa, DAF_DYNAMIC | DAF_FORK | DAF_ERASE);
Refresh();
m_accList.Enable();
@@ -875,7 +873,7 @@ void CAccountFormDlg::OnOk(CCtrlButton*)
wchar_t szPlugin[MAX_PATH];
mir_snwprintf(szPlugin, L"%s.dll", _A2T(m_pa->szProtoName));
int idx = accounts.getIndex(m_pa);
- UnloadAccount(m_pa, false, false);
+ UnloadAccount(m_pa, 0);
accounts.remove(idx);
if (oldProto && UnloadPlugin(szPlugin, _countof(szPlugin))) {
wchar_t szNewName[MAX_PATH];
diff --git a/src/mir_core/src/threads.cpp b/src/mir_core/src/threads.cpp
index a71d366585..de9474a101 100644
--- a/src/mir_core/src/threads.cpp
+++ b/src/mir_core/src/threads.cpp
@@ -208,12 +208,9 @@ MIR_CORE_DLL(HANDLE) mir_forkthreadowner(pThreadFuncOwner aFunc, void *owner, vo
/////////////////////////////////////////////////////////////////////////////////////////
-MIR_CORE_DLL(void) KillObjectThreads(void* owner)
+static void __cdecl KillObjectThreadsWorker(void* owner)
{
- if (owner == nullptr)
- return;
-
- HANDLE *threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE));
+ HANDLE *threadPool = (HANDLE*)alloca(threads.getCount() * sizeof(HANDLE));
int threadCount = 0;
{
mir_cslock lck(csThreads);
@@ -224,22 +221,44 @@ MIR_CORE_DLL(void) KillObjectThreads(void* owner)
}
// is there anything to kill?
- if (threadCount > 0) {
- if (WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) {
- // forcibly kill all remaining threads after 5 secs
- mir_cslock lck(csThreads);
- auto T = threads.rev_iter();
- for (auto &it : T) {
- if (it->pObject == owner) {
- char szModuleName[MAX_PATH];
- GetModuleFileNameA(it->hOwner, szModuleName, sizeof(szModuleName));
- Netlib_Logf(nullptr, "Killing object thread %s:%p", szModuleName, it->dwThreadId);
- TerminateThread(it->hThread, 9999);
- CloseHandle(it->hThread);
- mir_free(it);
- threads.remove(T.indexOf(&it));
- }
- }
+ if (threadCount == 0)
+ return;
+
+ // wait'em all
+ if (WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) != WAIT_TIMEOUT)
+ return;
+
+ // forcibly kill all remaining threads after 5 secs
+ mir_cslock lck(csThreads);
+ auto T = threads.rev_iter();
+ for (auto &it : T) {
+ if (it->pObject == owner) {
+ char szModuleName[MAX_PATH];
+ GetModuleFileNameA(it->hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf(nullptr, "Killing object thread %s:%p", szModuleName, it->dwThreadId);
+ TerminateThread(it->hThread, 9999);
+ CloseHandle(it->hThread);
+ mir_free(it);
+ threads.remove(T.indexOf(&it));
+ }
+ }
+}
+
+MIR_CORE_DLL(void) KillObjectThreads(void* owner)
+{
+ if (owner == nullptr)
+ return;
+
+ DWORD dwTicks = GetTickCount() + 6000;
+ HANDLE hThread = mir_forkthread(KillObjectThreadsWorker, owner);
+ while (GetTickCount() < dwTicks) {
+ if (WAIT_OBJECT_0 == MsgWaitForMultipleObjectsEx(1, &hThread, 50, QS_ALLPOSTMESSAGE | QS_ALLINPUT, MWMO_ALERTABLE))
+ break;
+
+ MSG msg;
+ while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
}
}
}