1
0
Fork 0
mirror of https://github.com/deltachat/deltachat-core.git synced 2025-10-05 10:39:27 +02:00

protect against race-condition when interupt() is called while perform-jobs() is running

This commit is contained in:
B. Petersen 2018-06-14 23:22:29 +02:00
parent bd33e707b8
commit c1108adc33
3 changed files with 53 additions and 12 deletions

View file

@ -680,6 +680,10 @@ void mrmailbox_perform_jobs(mrmailbox_t* mailbox)
{
mrmailbox_log_info(mailbox, 0, ">>>>> IMAP-jobs started.");
pthread_mutex_lock(&mailbox->m_imapidle_condmutex);
mailbox->m_perform_imap_jobs_needed = 0;
pthread_mutex_unlock(&mailbox->m_imapidle_condmutex);
mrjob_perform(mailbox, MR_IMAP_THREAD);
mrmailbox_log_info(mailbox, 0, "<<<<< IMAP-jobs ended.");
@ -723,6 +727,14 @@ void mrmailbox_idle(mrmailbox_t* mailbox)
// no return!
}
pthread_mutex_lock(&mailbox->m_imapidle_condmutex);
if( mailbox->m_perform_imap_jobs_needed ) {
mrmailbox_log_info(mailbox, 0, "IMAP-IDLE skipped.");
pthread_mutex_unlock(&mailbox->m_imapidle_condmutex);
return;
}
pthread_mutex_unlock(&mailbox->m_imapidle_condmutex);
mrmailbox_log_info(mailbox, 0, ">>>>> IMAP-IDLE started.");
mrimap_watch_n_wait(mailbox->m_imap);
@ -747,6 +759,13 @@ void mrmailbox_interrupt_idle(mrmailbox_t* mailbox)
mrmailbox_log_info(mailbox, 0, "> > > interrupt IMAP-IDLE.");
pthread_mutex_lock(&mailbox->m_imapidle_condmutex);
// when this function is called, it might be that the idle-thread is in
// perform_idle_jobs() instead of idle(). if so, added jobs will be performed after the _next_ idle-jobs loop.
// setting the flag perform_imap_jobs_needed makes sure, idle() returns immediately in this case.
mailbox->m_perform_imap_jobs_needed = 1;
pthread_mutex_unlock(&mailbox->m_imapidle_condmutex);
mrimap_interrupt_watch(mailbox->m_imap);
}
@ -760,6 +779,10 @@ void mrmailbox_perform_smtp_jobs(mrmailbox_t* mailbox)
{
mrmailbox_log_info(mailbox, 0, ">>>>> SMTP-jobs started.");
pthread_mutex_lock(&mailbox->m_smtpidle_condmutex);
mailbox->m_perform_smtp_jobs_needed = 0;
pthread_mutex_unlock(&mailbox->m_smtpidle_condmutex);
mrjob_perform(mailbox, MR_SMTP_THREAD);
mrmailbox_log_info(mailbox, 0, "<<<<< SMTP-jobs ended.");
@ -777,18 +800,25 @@ void mrmailbox_perform_smtp_idle(mrmailbox_t* mailbox)
pthread_mutex_lock(&mailbox->m_smtpidle_condmutex);
mailbox->m_smtpidle_in_idleing = 1; // checked in suspend(), for idle-interruption the pthread-condition below is used
int r = 0;
struct timespec timeToWait;
timeToWait.tv_sec = time(NULL)+60;
timeToWait.tv_nsec = 0;
while( mailbox->m_smtpidle_condflag == 0 && mailbox->m_smtpidle_suspend == 0 && r == 0 ) {
r = pthread_cond_timedwait(&mailbox->m_smtpidle_cond, &mailbox->m_smtpidle_condmutex, &timeToWait); // unlock mutex -> wait -> lock mutex
if( mailbox->m_perform_smtp_jobs_needed )
{
mrmailbox_log_info(mailbox, 0, "SMTP-idle skipped.");
}
mailbox->m_smtpidle_condflag = 0;
else
{
mailbox->m_smtpidle_in_idleing = 1; // checked in suspend(), for idle-interruption the pthread-condition below is used
mailbox->m_smtpidle_in_idleing = 0;
int r = 0;
struct timespec timeToWait;
timeToWait.tv_sec = time(NULL)+60;
timeToWait.tv_nsec = 0;
while( mailbox->m_smtpidle_condflag == 0 && mailbox->m_smtpidle_suspend == 0 && r == 0 ) {
r = pthread_cond_timedwait(&mailbox->m_smtpidle_cond, &mailbox->m_smtpidle_condmutex, &timeToWait); // unlock mutex -> wait -> lock mutex
}
mailbox->m_smtpidle_condflag = 0;
mailbox->m_smtpidle_in_idleing = 0;
}
pthread_mutex_unlock(&mailbox->m_smtpidle_condmutex);
@ -807,6 +837,11 @@ void mrmailbox_interrupt_smtp_idle(mrmailbox_t* mailbox)
pthread_mutex_lock(&mailbox->m_smtpidle_condmutex);
// when this function is called, it might be that the smtp-thread is in
// perform_smtp_jobs(). if so, added jobs will be performed after the _next_ idle-jobs loop.
// setting the flag perform_smtp_jobs_needed makes sure, idle() returns immediately in this case.
mailbox->m_perform_smtp_jobs_needed = 1;
mailbox->m_smtpidle_condflag = 1;
pthread_cond_signal(&mailbox->m_smtpidle_cond);

View file

@ -48,14 +48,18 @@ struct _mrmailbox
char* m_blobdir; /**< Full path of the blob directory. This is the directory given to mrmailbox_new() or a directory in the same directory as mrmailbox_t::m_dbfile. */
mrsqlite3_t* m_sql; /**< Internal SQL object, never NULL */
mrimap_t* m_imap; /**< Internal IMAP object, never NULL */
mrsmtp_t* m_smtp; /**< Internal SMTP object, never NULL */
mrimap_t* m_imap; /**< Internal IMAP object, never NULL */
pthread_mutex_t m_imapidle_condmutex;
int m_perform_imap_jobs_needed;
mrsmtp_t* m_smtp; /**< Internal SMTP object, never NULL */
pthread_cond_t m_smtpidle_cond;
pthread_mutex_t m_smtpidle_condmutex;
int m_smtpidle_condflag;
int m_smtpidle_suspend;
int m_smtpidle_in_idleing;
int m_perform_smtp_jobs_needed;
mrmailboxcb_t m_cb; /**< Internal */

View file

@ -105,6 +105,7 @@ mrmailbox_t* mrmailbox_new(mrmailboxcb_t cb, void* userdata, const char* os_name
}
pthread_mutex_init(&ths->m_log_ringbuf_critical, NULL);
pthread_mutex_init(&ths->m_imapidle_condmutex, NULL);
pthread_mutex_init(&ths->m_smtpidle_condmutex, NULL);
pthread_cond_init(&ths->m_smtpidle_cond, NULL);
@ -167,6 +168,7 @@ void mrmailbox_unref(mrmailbox_t* mailbox)
mrsqlite3_unref(mailbox->m_sql);
pthread_mutex_destroy(&mailbox->m_log_ringbuf_critical);
pthread_mutex_destroy(&mailbox->m_imapidle_condmutex);
pthread_cond_destroy(&mailbox->m_smtpidle_cond);
pthread_mutex_destroy(&mailbox->m_smtpidle_condmutex);