int DeleteAccounts(HYAMNPROTOPLUGIN Plugin) { HACCOUNT Finder; //1. wait to get write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write enter\n"); #endif WaitForAllAccounts(Plugin,FALSE); for (Finder=Plugin->FirstAccount;Finder != NULL;) { HACCOUNT Next = Finder->Next; DeletePluginAccountSvc((WPARAM)Finder,0); Finder = Next; } //leave write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); return 1; }
int StopAccounts(HYAMNPROTOPLUGIN Plugin) { HACCOUNT Finder; //1. wait to get write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write enter\n"); #endif for (Finder=Plugin->FirstAccount;Finder != NULL;Finder=Finder->Next) { //2. set stop signal StopSignalFcn(Finder); WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_STOPACCOUNT,(WPARAM)Finder,0); if (Plugin->Fcn->StopAccountFcnPtr != NULL) Plugin->Fcn->StopAccountFcnPtr(Finder); } //leave write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); //Now, account is stopped. It can be removed from memory... return 1; }
DWORD WINAPI WaitToWriteFcn(PSWMRG SObject,PSCOUNTER SCounter) { DWORD EnterCode; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"\tSO WaitToWrite: %x\n",SObject); #endif if(WAIT_OBJECT_0==(EnterCode=SWMRGWaitToWrite(SObject,INFINITE))) if(SCounter!=NULL) SCIncFcn(SCounter); return EnterCode; }
int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin,BOOL GetAccountBrowserAccess) { HACCOUNT Finder; if (GetAccountBrowserAccess) { //1. wait to get write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write enter\n"); #endif } for (Finder=Plugin->FirstAccount;Finder != NULL;Finder=Finder->Next) { //2. wait for signal that account is not in use #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"WaitForAllAccounts:waiting for UsingThreadEV %x (account %x)\n",Finder->UsingThreads,Finder); #endif WaitForSingleObject(Finder->UsingThreads->Event,INFINITE); SetEvent(Finder->UsingThreads->Event); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"WaitForAllAccounts:UsingThreadEV signaled\n"); #endif } if (GetAccountBrowserAccess) { //leave write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); } return 1; }
static INT_PTR PerformAccountReading(HYAMNPROTOPLUGIN Plugin,char *MemFile,char *End) { //Retrieve info for account from memory char *Parser; DWORD Ver,Stat; HACCOUNT ActualAccount,FirstAllocatedAccount; Ver=*(DWORD *)MemFile; if (Ver>YAMN_ACCOUNTFILEVERSION) { delete[] MemFile; return EACC_FILEVERSION; } Parser=MemFile+sizeof(Ver); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write enter\n"); #endif if (NULL==(ActualAccount=(HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT,(WPARAM)Plugin,(LPARAM)YAMN_ACCOUNTVERSION))) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); delete[] MemFile; return EACC_ALLOC; } FirstAllocatedAccount=ActualAccount; do { HACCOUNT Temp; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write wait\n"); #endif WaitToWriteFcn(ActualAccount->AccountAccessSO); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write enter\n"); #endif Stat=ReadAccountFromMemory(ActualAccount,&Parser,End); if (ActualAccount->StatusFlags & (YAMN_ACC_STARTA | YAMN_ACC_STARTS)) ActualAccount->TimeLeft=1; //check on loading if (Stat && (Stat != EACC_ENDOFFILE)) { for (ActualAccount=FirstAllocatedAccount;ActualAccount != NULL;ActualAccount=Temp) { Temp=ActualAccount->Next; delete ActualAccount; } delete[] MemFile; if (Plugin->FirstAccount==FirstAllocatedAccount) Plugin->FirstAccount=NULL; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); return (INT_PTR)Stat; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write done\n"); #endif WriteDoneFcn(ActualAccount->AccountAccessSO); if ((Stat != EACC_ENDOFFILE) && (NULL==(ActualAccount=(HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT,(WPARAM)Plugin,(LPARAM)YAMN_ACCOUNTVERSION)))) { for (ActualAccount=FirstAllocatedAccount;ActualAccount != NULL;ActualAccount=Temp) { Temp=ActualAccount->Next; delete ActualAccount; } delete[] MemFile; if (Plugin->FirstAccount==FirstAllocatedAccount) Plugin->FirstAccount=NULL; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); return EACC_ALLOC; } }while(Stat != EACC_ENDOFFILE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); delete[] MemFile; return 0; }
/* int FindPluginAccount(WPARAM wParam,LPARAM lParam) { HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; HACCOUNT Finder=(HACCOUNT)lParam; if (Finder=NULL) Finder=Plugin->FirstAccount; // for (;Finder != NULL && Finder->PluginID != Plugin->PluginInfo->PluginID;Finder=(HACCOUNT)Finder->Next); return (int)Finder; } */ INT_PTR DeleteAccountSvc(WPARAM wParam,LPARAM lParam) { //Deleting account works on these steps: //1. set signal that account should stop activity (set event) // setting this event we achieve, that any access to account is failed, // so threads do not start any work with accounts (better saying threads of plugins should not start) //2. wait to get write access to chained list of accounts //3. we can write to chained list, so we change chain not to show to actual account // now, any thread browsing list of accounts does not browse through actual account // actual account seems to be hidden (it exists, but it is not in accounts chained list (chained list=queue)) //Now, we should delete account from memory, BUT!!! // Any thread can still be waked up and start asking account synchronizing object // If account is deleted, asking about access to read account can throw memory exception (reading for // a synchronizing object from memory, that was deleted) //So, we cannot now delete account. We have to wait until we are sure no thread will be using account anymore // (or to the end of Miranda, but problem is in allocated memory- it is allocated and Miranda is SMALLER, faster, easier, isn't it?) // This deleting is achieved in 2 ways: // We have event in UsingThreads synchronization objects. This event signals that no thread will use actual account // 1. Any thread using account first increment UsingThread, so we know that account is used // 2. If thread is about to close, it should decrement UsingThread // 3. If thread creates another thread, that will use account, caller has to wait until the new thread does not // increment UsingThreads (imagine that caller ends before the new thread set it: if no other thread is using // account, account is automaticaly (decreasing UsingThreads) signaled as "not used" and we delete it. But then // new thread is going to read account...). //4. wait until UsingThread Event is signaled //5. delete account from memory HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; HACCOUNT Which=(HACCOUNT)lParam; HACCOUNT Finder; DWORD tid; //1. set stop signal StopSignalFcn(Which); WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_STOPACCOUNT,(WPARAM)Which,0); if (Plugin->Fcn->StopAccountFcnPtr != NULL) Plugin->Fcn->StopAccountFcnPtr(Which); //2. wait to get write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write wait\n"); #endif SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write enter\n"); #endif //3. remove from queue (chained list) if (Plugin->FirstAccount==NULL) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); return 0; } if (Plugin->FirstAccount==Which) { Finder=Plugin->FirstAccount->Next; Plugin->FirstAccount=Finder; } else { for (Finder=Plugin->FirstAccount;Which != Finder->Next;Finder=Finder->Next); Finder->Next=Finder->Next->Next; } //leave write access #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); #endif SWMRGDoneWriting(Plugin->AccountBrowserSO); //4. wait while event "UsingThread" is not signaled // And what to do, if this event will be signaled in 1 hour? (Although it's paranoia, because we have sent "delete signal", so // other threads do not start any new work with actual account) We will wait in blocked state? // No, of course not. We will create new thread, that will wait and additionally remove our thread in background. //5. So, the last point (deleting from memory) is performed in new DeleteAccountInBackground thread if ((Plugin->Fcn != NULL) && (Plugin->Fcn->WriteAccountsFcnPtr != NULL)) Plugin->Fcn->WriteAccountsFcnPtr(); CloseHandle(CreateThread(NULL,0,DeleteAccountInBackground,(LPVOID)Which,0,&tid)); //Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using //event UsingThreads. return 1; }