Commit 18406256 18406256a580340a70c9f5ef452f7b79621529d8 by Alain Magloire

Making the library more thread aware. This is an attempt to be Cancel-safe

or at least cancel friendly.
1 parent 06aea14d
......@@ -21,13 +21,39 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#include <mailutils/registrar.h>
#include <mailutils/iterator.h>
#include <mailutils/list.h>
#include <misc.h>
#include <folder0.h>
#ifdef WITH_PTHREAD
static pthread_mutex_t slock = PTHREAD_MUTEX_INITIALIZER;
#endif
/* Internal folder list. */
static list_t known_folder_list;
static int is_known_folder (url_t, folder_t *);
static int is_same_scheme (url_t, url_t);
static int is_same_user (url_t, url_t);
static int is_same_path (url_t, url_t);
static int is_same_host (url_t, url_t);
static int is_same_port (url_t, url_t);
/* A folder could be a remote one, IMAP, or local, a spool directory
like $HOME/Mail etc .. We maintain a known list of folder to
not generate multiple folder of the same URL. Meaning when
folder_create () is call we'll check if we already have a
folder for that URL and return the same, if not we create a new one.
The downside, the algo to detect the same URL is very weak, and
they maybe cases where you want a different folder for the same
URL, there is not easy way to do this. */
int
folder_create (folder_t *pfolder, const char *name)
{
......@@ -41,7 +67,7 @@ folder_create (folder_t *pfolder, const char *name)
if (pfolder == NULL)
return EINVAL;
/* Look in the registrar, for a match */
/* Look in the registrar list(iterator), for a match */
registrar_get_list (&list);
status = iterator_create (&iterator, list);
if (status != 0)
......@@ -67,38 +93,63 @@ folder_create (folder_t *pfolder, const char *name)
url_t url = NULL;
folder_t folder = NULL;
/* Allocate memory for mbox. */
folder = calloc (1, sizeof (*folder));
if (folder == NULL)
return ENOMEM;
/* Initialize the internal lock, now so the concrete mailbox
could use it. */
status = RWLOCK_INIT (&(folder->rwlock), NULL);
if (status != 0)
{
folder_destroy (&folder);
return status;
}
/* Parse the url, it may be a bad one and we should bailout if this
failed. */
if ((status = url_create (&url, name)) != 0
if ((status = url_create (&url, name) != 0)
|| (status = entry->_url_init (url)) != 0)
{
folder_destroy (&folder);
return status;
#ifdef WITH_PTHREAD
pthread_mutex_lock (&slock);
#endif
/* Check if we already have the same URL folder. */
if (is_known_folder (url, &folder))
{
folder->ref++;
*pfolder = folder;
url_destroy (&url);
#ifdef WITH_PTHREAD
pthread_mutex_unlock (&slock);
#endif
return 0;
}
folder->url = url;
#ifdef WITH_PTHREAD
else
pthread_mutex_unlock (&slock);
#endif
/* Create a new folder. */
/* Allocate memory for folder. */
folder = calloc (1, sizeof (*folder));
if (folder != NULL)
{
folder->url = url;
/* Initialize the internal lock, now so the concrete
folder could use it. */
status = monitor_create (&(folder->monitor), folder);
if (status == 0)
{
/* Create the concrete folder type. */
status = entry->_folder_init (folder);
if (status == 0)
{
*pfolder = folder;
folder->ref++;
/* Put on the internal list of known folders. */
list_append (known_folder_list, folder);
}
}
/* Something went wrong, destroy the object. */
if (status != 0)
{
folder_destroy (&folder);
if (folder->monitor)
monitor_destroy (&(folder->monitor), folder);
if (folder->url)
url_destroy (&(folder->url));
free (folder);
}
}
else
*pfolder = folder;
}
else
status = ENOENT;
......@@ -113,13 +164,26 @@ folder_destroy (folder_t *pfolder)
{
folder_t folder = *pfolder;
int destroy_lock = 0;
monitor_t monitor = folder->monitor;
size_t reference;
monitor_wrlock (monitor);
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock = folder->rwlock;
pthread_mutex_lock (&slock);
#endif
RWLOCK_WRLOCK (&(rwlock));
if (folder_decremente (folder) == 0)
{
RWLOCK_UNLOCK (&(rwlock));
folder->ref--;
reference = folder->ref;
/* Remove the folder from the list of known folder. */
if (reference == 0)
list_remove (known_folder_list, folder);
}
#ifdef WITH_PHTREAD
pthread_mutex_unlock (&slock);
#endif
if (reference == 0)
{
monitor_unlock (monitor);
destroy_lock = 1;
/* Notify the observers. */
if (folder->observable)
......@@ -129,7 +193,7 @@ folder_destroy (folder_t *pfolder)
}
if (folder->_destroy)
folder->_destroy (folder);
RWLOCK_WRLOCK (&(rwlock));
monitor_wrlock (monitor);
if (folder->ticket)
ticket_destroy (&(folder->ticket), folder);
if (folder->authority)
......@@ -140,9 +204,9 @@ folder_destroy (folder_t *pfolder)
url_destroy (&(folder->url));
free (folder);
}
RWLOCK_UNLOCK (&(rwlock));
monitor_unlock (monitor);
if (destroy_lock)
RWLOCK_DESTROY (&(rwlock));
monitor_destroy (&monitor, folder);
*pfolder = NULL;
}
}
......@@ -281,10 +345,144 @@ folder_delete_mailbox (folder_t folder, const char *name)
return folder->_delete_mailbox (folder, name);
}
int
folder_decremente (folder_t folder)
static int is_known_folder (url_t url, folder_t *pfolder)
{
if (folder && folder->_decremente)
return folder->_decremente (folder);
return (folder->ref--);
int ret = 0;
folder_t folder = NULL;
iterator_t iterator;
if (url == NULL || pfolder == NULL)
return ret;
if (iterator_create (&iterator, known_folder_list) != 0)
return ret;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&folder);
/* Check if the same URL type. */
if (folder && folder->url
&& is_same_scheme (url, folder->url)
&& is_same_user (url, folder->url)
&& is_same_path (url, folder->url)
&& is_same_host (url, folder->url)
&& is_same_port (url, folder->url))
{
ret = 1;
break;
}
}
iterator_destroy (&iterator);
return ret;
}
static int
is_same_scheme (url_t url1, url_t url2)
{
int i = 0, j = 0;
char *s1, *s2;
int ret = 1;
url_get_scheme (url1, NULL, 0, &i);
url_get_scheme (url2, NULL, 0, &j);
s1 = calloc (i + 1, sizeof (char));
if (s1)
{
url_get_scheme (url1, s1, i + 1, NULL);
s2 = calloc (j + 1, sizeof (char));
if (s2)
{
url_get_scheme (url2, s2, j + 1, NULL);
ret = !strcasecmp (s1, s2);
free (s2);
}
free (s1);
}
return ret;
}
static int
is_same_user (url_t url1, url_t url2)
{
int i = 0, j = 0;
char *s1, *s2;
int ret = 0;
url_get_user (url1, NULL, 0, &i);
url_get_user (url2, NULL, 0, &j);
s1 = calloc (i + 1, sizeof (char));
if (s1)
{
url_get_user (url1, s1, i + 1, NULL);
s2 = calloc (j + 1, sizeof (char));
if (s2)
{
url_get_user (url2, s2, j + 1, NULL);
ret = !strcasecmp (s1, s2);
free (s2);
}
free (s1);
}
return ret;
}
static int
is_same_path (url_t url1, url_t url2)
{
int i = 0, j = 0;
char *s1, *s2;
int ret = 0;
url_get_path (url1, NULL, 0, &i);
url_get_path (url2, NULL, 0, &j);
s1 = calloc (i + 1, sizeof (char));
if (s1)
{
url_get_path (url1, s1, i + 1, NULL);
s2 = calloc (j + 1, sizeof (char));
if (s2)
{
url_get_path (url2, s2, j + 1, NULL);
ret = !strcasecmp (s1, s2);
free (s2);
}
free (s1);
}
return ret;
}
static int
is_same_host (url_t url1, url_t url2)
{
int i = 0, j = 0;
char *s1, *s2;
int ret = 0;
url_get_host (url1, NULL, 0, &i);
url_get_host (url2, NULL, 0, &j);
s1 = calloc (i + 1, sizeof (char));
if (s1)
{
url_get_host (url1, s1, i + 1, NULL);
s2 = calloc (j + 1, sizeof (char));
if (s2)
{
url_get_host (url2, s2, j + 1, NULL);
ret = !strcasecmp (s1, s2);
free (s2);
}
free (s1);
}
return ret;
}
static int
is_same_port (url_t url1, url_t url2)
{
long p1 = 0, p2 = 0;
url_get_port (url1, &p1);
url_get_port (url2, &p2);
return (p1 == p2);
}
......
......@@ -22,14 +22,10 @@
# include <dmalloc.h>
#endif
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98 /* ?? */
# include <pthread.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#include <mailutils/monitor.h>
#include <mailutils/folder.h>
#ifdef __cplusplus
......@@ -52,15 +48,12 @@ struct _folder
observable_t observable;
debug_t debug;
stream_t stream;
monitor_t monitor;
url_t url;
int flags;
size_t ref;
size_t uid;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock;
#endif
/* Back pointer to the specific mailbox */
void *data;
......@@ -73,13 +66,8 @@ struct _folder
int (*_close) __P ((folder_t));
int (*_list) __P ((folder_t, list_t *));
int (*_delete_mailbox) __P ((folder_t, const char *));
int (*_decremente) __P ((folder_t));
};
/* To manipulate mailbox rwlock. */
extern int folder_rdlock __P ((folder_t));
extern int folder_wrlock __P ((folder_t));
extern int folder_unlock __P ((folder_t));
#ifdef __cplusplus
}
......
......@@ -22,13 +22,10 @@
# include <dmalloc.h>
#endif
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98 /* ?? */
# include <pthread.h>
#endif
#include <sys/types.h>
#include <mailutils/list.h>
#include <sys/types.h>
#include <mailutils/monitor.h>
#ifndef __P
......@@ -54,9 +51,7 @@ struct _list
{
struct list_data head;
size_t count;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock;
#endif
monitor_t monitor;
};
......
......@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <stdio.h>
#include <mailutils/monitor.h>
#include <mailutils/mailbox.h>
#include <mailutils/folder.h>
......@@ -57,10 +58,7 @@ struct _mailbox
url_t url;
folder_t folder;
int flags;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock;
#endif
monitor_t monitor;
/* Back pointer to the specific mailbox */
void *data;
......@@ -86,11 +84,6 @@ struct _mailbox
};
/* To manipulate mailbox rwlock. */
extern int mailbox_rdlock __P ((mailbox_t));
extern int mailbox_wrlock __P ((mailbox_t));
extern int mailbox_unlock __P ((mailbox_t));
#define MAILBOX_NOTIFY(mbox, type) \
if (mbox->observer) observer_notify (mbox->observer, type)
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MONITOR0_H
#define _MONITOR0_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <mailutils/monitor.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# if __STDC__
# define __P(x) x
# else
# define __P(x)
# endif
#endif
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98
# include <pthread.h>
#endif
#ifdef WITH_PTHREAD
# if 0
# define RWLOCK_INIT(rwl, attr) pthread_mutex_init (rwl, attr)
# define RWLOCK_DESTROY(rwl) pthread_mutex_destroy (rwl)
# define RWLOCK_RDLOCK(rwl) pthread_mutex_lock (rwl)
# define RWLOCK_TRYRDLOCK(rwl) pthread_mutex_trylock (rwl)
# define RWLOCK_WRLOCK(rwl) pthread_mutex_lock (rwl)
# define RWLOCK_TRYWRLOCK(rwl) pthread_mutex_trylock (rwl)
# define RWLOCK_UNLOCK(rwl) pthread_mutex_unlock (rwl)
# else
# define RWLOCK_INIT(rwl, attr) pthread_rwlock_init (rwl, attr)
# define RWLOCK_DESTROY(rwl) pthread_rwlock_destroy (rwl)
# define RWLOCK_RDLOCK(rwl) pthread_rwlock_rdlock (rwl)
# define RWLOCK_TRYRDLOCK(rwl) pthread_rwlock_tryrdlock (rwl)
# define RWLOCK_WRLOCK(rwl) pthread_rwlock_wrlock (rwl)
# define RWLOCK_TRYWRLOCK(rwl) pthread_rwlock_trywrlock (rwl)
# define RWLOCK_UNLOCK(rwl) pthread_rwlock_unlock (rwl)
# endif
#else
# define RWLOCK_INIT(rwl, attr) 0
# define RWLOCK_DESTROY(rwl) 0
# define RWLOCK_RDLOCK(rwl) 0
# define RWLOCK_TRYRDLOCK(rwl) 0
# define RWLOCK_WRLOCK(rwl) 0
# define RWLOCK_TRYWRLOCK(rwl) 0
# define RWLOCK_UNLOCK(rwl) 0
# define flockfile(arg) 0
# define funlockfile(arg) 0
#endif
struct _monitor
{
#ifdef WITH_PTHREAD
pthread_rwlock_t lock;
#else
int lock;
#endif
void *owner;
};
#ifdef __cplusplus
}
#endif
#endif /* _MONITOR0_H */
......@@ -22,7 +22,6 @@
#include <errno.h>
#include <stdlib.h>
#include <misc.h>
#include <list0.h>
int
......@@ -35,7 +34,7 @@ list_create (list_t *plist)
list = calloc (sizeof (*list), 1);
if (list == NULL)
return ENOMEM;
status = RWLOCK_INIT (&(list->rwlock), NULL);
status = monitor_create (&(list->monitor), list);
if (status != 0)
{
free (list);
......@@ -55,15 +54,15 @@ list_destroy (list_t *plist)
list_t list = *plist;
struct list_data *current;
struct list_data *previous;
RWLOCK_WRLOCK (&(list->rwlock));
monitor_wrlock (list->monitor);
for (current = list->head.next; current != &(list->head);)
{
previous = current;
current = current->next;
free (previous);
}
RWLOCK_UNLOCK (&(list->rwlock));
RWLOCK_DESTROY (&(list->rwlock));
monitor_unlock (list->monitor);
monitor_destroy (&(list->monitor), list);
free (list);
*plist = NULL;
}
......@@ -78,13 +77,13 @@ list_append (list_t list, void *item)
if (ldata == NULL)
return ENOMEM;
ldata->item = item;
RWLOCK_WRLOCK (&(list->rwlock));
monitor_wrlock (list->monitor);
ldata->next = &(list->head);
ldata->prev = list->head.prev;
last->next = ldata;
list->head.prev = ldata;
list->count++;
RWLOCK_UNLOCK (&(list->rwlock));
monitor_unlock (list->monitor);
return 0;
}
......@@ -97,13 +96,13 @@ list_prepend (list_t list, void *item)
if (ldata == NULL)
return ENOMEM;
ldata->item = item;
RWLOCK_WRLOCK (&(list->rwlock));
monitor_wrlock (list->monitor);
ldata->prev = &(list->head);
ldata->next = list->head.next;
first->prev = ldata;
list->head.next = ldata;
list->count++;
RWLOCK_UNLOCK (&(list->rwlock));
monitor_unlock (list->monitor);
return 0;
}
......@@ -130,7 +129,7 @@ list_remove (list_t list, void *item)
struct list_data *current, *previous;
if (list == NULL)
return EINVAL;
RWLOCK_WRLOCK (&(list->rwlock));
monitor_wrlock (list->monitor);
for (previous = &(list->head), current = list->head.next;
current != &(list->head); previous = current, current = current->next)
{
......@@ -140,11 +139,11 @@ list_remove (list_t list, void *item)
current->next->prev = previous;
free (current);
list->count--;
RWLOCK_UNLOCK (&(list->rwlock));
monitor_unlock (list->monitor);
return 0;
}
}
RWLOCK_UNLOCK (&(list->rwlock));
monitor_unlock (list->monitor);
return ENOENT;
}
......@@ -155,17 +154,17 @@ list_get (list_t list, size_t index, void **pitem)
size_t count;
if (list == NULL || pitem == NULL)
return EINVAL;
RWLOCK_RDLOCK (&(list->rwlock));
monitor_rdlock (list->monitor);
for (current = list->head.next, count = 0; current != &(list->head);
current = current->next, count++)
{
if (count == index)
{
*pitem = current->item;
RWLOCK_UNLOCK (&(list->rwlock));
monitor_unlock (list->monitor);
return 0;
}
}
RWLOCK_UNLOCK (&(list->rwlock));
monitor_unlock (list->monitor);
return ENOENT;
}
......
......@@ -22,10 +22,8 @@
#include <stdlib.h>
#include <errno.h>
#include <mailutils/locker.h>
#include <mailutils/iterator.h>
#include <mailutils/registrar.h>
#include <misc.h>
#include <mailbox0.h>
/* The Mailbox Factory.
......@@ -77,9 +75,9 @@ mailbox_create (mailbox_t *pmbox, const char *name)
if (mbox == NULL)
return ENOMEM;
/* Initialize the internal lock, now so the concrete mailbox
/* Initialize the internal lock now, so the concrete mailbox
could use it. */
status = RWLOCK_INIT (&(mbox->rwlock), NULL);
status = monitor_create (&(mbox->monitor), mbox);
if (status != 0)
{
mailbox_destroy (&mbox);
......@@ -117,9 +115,7 @@ mailbox_destroy (mailbox_t *pmbox)
if (pmbox && *pmbox)
{
mailbox_t mbox = *pmbox;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock = mbox->rwlock;
#endif
monitor_t monitor = mbox->monitor;
/* Notify the observers. */
if (mbox->observable)
......@@ -132,7 +128,7 @@ mailbox_destroy (mailbox_t *pmbox)
if (mbox->_destroy)
mbox->_destroy (mbox);
RWLOCK_WRLOCK (&(rwlock));
monitor_wrlock (monitor);
/* Nuke the stream and close it */
if (mbox->stream)
......@@ -161,8 +157,8 @@ mailbox_destroy (mailbox_t *pmbox)
free (mbox);
*pmbox = NULL;
RWLOCK_UNLOCK (&(rwlock));
RWLOCK_DESTROY (&(rwlock));
monitor_unlock (monitor);
monitor_destroy (&monitor, mbox);
}
}
......@@ -317,7 +313,7 @@ mailbox_set_stream (mailbox_t mbox, stream_t stream)
int
mailbox_get_stream (mailbox_t mbox, stream_t *pstream)
{
if (mbox == NULL || pstream == NULL)
if (mbox == NULL || pstream)
return EINVAL;
*pstream = mbox->stream;
return 0;
......@@ -364,42 +360,3 @@ mailbox_get_debug (mailbox_t mbox, debug_t *pdebug)
*pdebug = mbox->debug;
return 0;
}
/* Mailbox Internal Locks. Put the name of the functions in parenteses To make
sure it will not be redefine by a macro. If the flags was non-blocking we
should not block on the lock, so we try with pthread_rwlock_try*lock(). */
int
(mailbox_rdlock) (mailbox_t mbox)
{
#ifdef WITH_PTHREAD
int err = (mbox->flags & MU_STREAM_NONBLOCK) ?
RWLOCK_TRYRDLOCK (&(mbox->rwlock)) :
RWLOCK_RDLOCK (&(mbox->rwlock)) ;
if (err != 0 && err != EDEADLK)
return err;
#endif
return 0;
}
int
(mailbox_wrlock) (mailbox_t mbox)
{
#ifdef WITH_PTHREAD
int err = (mbox->flags & MU_STREAM_NONBLOCK) ?
RWLOCK_TRYWRLOCK (&(mbox->rwlock)) :
RWLOCK_WRLOCK (&(mbox->rwlock)) ;
if (err != 0 && err != EDEADLK)
return err;
#endif
return 0;
}
int
(mailbox_unlock) (mailbox_t mbox)
{
#ifdef WITH_PTHREAD
return RWLOCK_UNLOCK (&(mbox->rwlock));
#else
return 0;
#endif
}
......
......@@ -33,6 +33,9 @@
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#include <mailutils/message.h>
#include <mailutils/stream.h>
......@@ -48,7 +51,7 @@
static int mbox_init (mailbox_t mailbox);
/* Register variables. */
/* Registrar variables. */
static struct mailbox_entry _mbox_entry =
{
url_mbox_init, mbox_init
......@@ -161,9 +164,7 @@ static int mbox_body_size (body_t, size_t *);
static int mbox_body_lines (body_t, size_t *);
static int mbox_msg_from (message_t, char *, size_t, size_t *);
static int mbox_msg_received (message_t, char *, size_t, size_t *);
static int mbox_lock (mailbox_t, int);
static int mbox_touchlock (mailbox_t);
static int mbox_unlock (mailbox_t);
static void mbox_cleanup (void *);
/* We allocate the mbox_data_t struct, but don't do any parsing on the name or
even test for existence. However we do strip any leading "mbox:" part of
......@@ -230,14 +231,13 @@ mbox_init (mailbox_t mailbox)
static void
mbox_destroy (mailbox_t mailbox)
{
mbox_close (mailbox);
if (mailbox->data)
{
size_t i;
mbox_data_t mud = mailbox->data;
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE,
"mbox_destroy (%s)\n", mud->name);
mailbox_wrlock (mailbox);
monitor_wrlock (mailbox->monitor);
for (i = 0; i < mud->umessages_count; i++)
{
mbox_message_t mum = mud->umessages[i];
......@@ -253,7 +253,7 @@ mbox_destroy (mailbox_t mailbox)
free (mud->name);
free (mud);
mailbox->data = NULL;
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
}
}
......@@ -268,7 +268,6 @@ mbox_open (mailbox_t mailbox, int flags)
return EINVAL;
mailbox->flags = flags | MU_STREAM_FILE;
mailbox_rdlock (mailbox);
/* Get a stream. */
if (mailbox->stream == NULL)
......@@ -282,36 +281,33 @@ mbox_open (mailbox_t mailbox, int flags)
{
status = file_stream_create (&(mailbox->stream));
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
}
status = stream_open (mailbox->stream, mud->name, 0, mailbox->flags);
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
}
else
{
status = stream_open (mailbox->stream, mud->name, 0, mailbox->flags);
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
}
MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_open(%s, %d)\n",
mud->name, mailbox->flags);
/* Give an appopriate way to lock. */
if (mailbox->authority)
{
status = authority_authenticate (mailbox->authority);
if (status != 0)
return status;
}
/* Give an appropriate way to file lock. */
if (mailbox->locker == NULL)
locker_create (&(mailbox->locker), mud->name, strlen (mud->name),
MU_LOCKER_PID | MU_LOCKER_FCNTL);
mailbox_unlock (mailbox);
return 0;
}
......@@ -324,11 +320,12 @@ mbox_close (mailbox_t mailbox)
if (mud == NULL)
return EINVAL;
/* Make sure we do not hold any lock for that file. */
mbox_unlock (mailbox);
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_close(%s)\n", mud->name);
mailbox_wrlock (mailbox);
/* Make sure that we do hold any file locking. */
locker_unlock (mailbox->locker);
monitor_wrlock (mailbox->monitor);
/* Before closing we need to remove all the messages
- to reclaim the memory
- to prepare for another scan. */
......@@ -347,7 +344,7 @@ mbox_close (mailbox_t mailbox)
mud->umessages = NULL;
mud->messages_count = mud->umessages_count = 0;
mud->size = 0;
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return stream_close (mailbox->stream);
}
......@@ -364,27 +361,23 @@ mbox_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
/* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
browsers and delete files in one. My views is that we should scream
browsers and deleted emails in one. My views is that we should scream
bloody murder and hunt them with a machette. But for now just play dumb,
but maybe the best approach is to pack our things and leave .i.e exit(). */
static int
mbox_is_updated (mailbox_t mailbox)
{
off_t size;
off_t size = 0;
mbox_data_t mud = mailbox->data;
int status;
if (mud == NULL)
return EINVAL;
mailbox_rdlock (mailbox);
if (stream_size (mailbox->stream, &size) != 0)
{
mailbox_unlock (mailbox);
return 0;
if (size < mud->size)
{
observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT);
/* And be verbose. */
fprintf (stderr, "Mailbox corrupted, shrink size\n");
}
status = (mud->size == size);
mailbox_unlock (mailbox);
return status;
return (mud->size == size);
}
/* FIXME: the use of tmpfile() on some system can lead to race condition, We
......@@ -464,6 +457,9 @@ mbox_expunge (mailbox_t mailbox)
off_t total = 0;
char buffer [BUFSIZ];
char *tmpmbox = NULL;
#ifdef WITH_PTHREAD
int state;
#endif
if (mud == NULL)
return EINVAL;
......@@ -481,7 +477,7 @@ mbox_expunge (mailbox_t mailbox)
return EAGAIN;
}
mailbox_wrlock (mailbox);
monitor_wrlock (mailbox->monitor);
/* Mark dirty the first mail with an attribute change. */
for (dirty = 0; dirty < mud->messages_count; dirty++)
......@@ -495,11 +491,10 @@ mbox_expunge (mailbox_t mailbox)
/* Did something change ? */
if (dirty == mud->messages_count)
{
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return 0; /* Nothing change, bail out. */
}
/* This is redundant, we go to the loop again. But it's more secure here
since we don't want to be disturb when expunging. */
for (j = 0; j < mud->messages_count; j++)
......@@ -513,24 +508,27 @@ mbox_expunge (mailbox_t mailbox)
tempfile = mbox_tmpfile (mailbox, &tmpmbox);
if (tempfile == NULL)
{
fprintf (stderr, "Failed to create temporary file when expunging.\n");
free (tmpmbox);
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
fprintf (stderr, "Failed to create temporary file when expunging.\n");
return errno;
}
/* Get the lock. */
if (mbox_lock (mailbox, MU_LOCKER_WRLOCK) < 0)
/* Get the File lock. */
if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) < 0)
{
fclose (tempfile);
remove (tmpmbox);
free (tmpmbox);
monitor_unlock (mailbox->monitor);
fprintf (stderr, "Failed to grab the lock\n");
mailbox_unlock (mailbox);
return ENOLCK;
}
/* Critical section, we can not allowed signal here. */
#ifdef WITH_PTHREAD
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
#endif
sigemptyset (&signalset);
sigaddset (&signalset, SIGTERM);
sigaddset (&signalset, SIGHUP);
......@@ -732,9 +730,12 @@ mbox_expunge (mailbox_t mailbox)
bailout:
free (tmpmbox);
/* Release the locks. */
mbox_unlock (mailbox);
/* Release the File lock. */
locker_unlock (mailbox->locker);
fclose (tempfile);
#ifdef WITH_PTHREAD
pthread_setcancelstate (state, &state);
#endif
sigprocmask (SIG_UNBLOCK, &signalset, 0);
/* We need to readjust the pointers. */
......@@ -775,11 +776,11 @@ mbox_expunge (mailbox_t mailbox)
}
/* This is should reset the messages_count, the last argument 0 means
not to send event notification. */
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
mbox_scan0 (mailbox, dirty, NULL, 0);
}
else
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return status;
}
......@@ -807,9 +808,7 @@ mbox_get_fd (mbox_message_t mum, int *pfd)
int status;
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
status = stream_get_fd (mum->stream, pfd);
mailbox_unlock (mum->mud->mailbox);
return status;
}
......@@ -821,11 +820,8 @@ mbox_get_attr_flags (attribute_t attr, int *pflags)
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (pflags)
*pflags = mum->new_flags;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
......@@ -837,10 +833,7 @@ mbox_set_attr_flags (attribute_t attr, int flags)
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
mum->new_flags |= flags;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
......@@ -852,10 +845,7 @@ mbox_unset_attr_flags (attribute_t attr, int flags)
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
mum->new_flags &= ~flags;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
......@@ -867,6 +857,7 @@ mbox_readstream (stream_t is, char *buffer, size_t buflen,
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
size_t nread = 0;
int status = 0;
if (mum == NULL)
return EINVAL;
......@@ -878,28 +869,30 @@ mbox_readstream (stream_t is, char *buffer, size_t buflen,
return 0;
}
mailbox_rdlock (mum->mud->mailbox);
monitor_rdlock (mum->mud->mailbox->monitor);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mum->mud->mailbox);
#endif
{
off_t ln = mum->body_end - (mum->body + off);
size_t n = 0;
int status;
if (ln > 0)
{
nread = ((size_t)ln < buflen) ? ln : buflen;
/* Position the file pointer and the buffer. */
status = stream_read (mum->stream, buffer, nread, mum->body + off, &n);
if (status != 0)
{
mailbox_unlock (mum->mud->mailbox);
return status;
}
}
}
mailbox_unlock (mum->mud->mailbox);
monitor_unlock (mum->mud->mailbox->monitor);
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
if (pnread)
*pnread = nread;
return 0;
return status;
}
static int
......@@ -916,7 +909,12 @@ mbox_get_header_read (stream_t is, char *buffer, size_t len,
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
monitor_rdlock (mum->mud->mailbox->monitor);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mum->mud->mailbox);
#endif
ln = mum->body - (mum->header_from_end + off);
if (ln > 0)
{
......@@ -925,9 +923,12 @@ mbox_get_header_read (stream_t is, char *buffer, size_t len,
status = stream_read (mum->stream, buffer, nread,
mum->header_from_end + off, &nread);
}
monitor_unlock (mum->mud->mailbox->monitor);
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
if (pnread)
*pnread = nread;
mailbox_unlock (mum->mud->mailbox);
return status;
}
......@@ -938,10 +939,8 @@ mbox_header_size (header_t header, size_t *psize)
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (psize)
*psize = mum->body - mum->header_from_end;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
......@@ -952,10 +951,8 @@ mbox_header_lines (header_t header, size_t *plines)
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (plines)
*plines = mum->header_lines;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
......@@ -978,10 +975,8 @@ mbox_body_lines (body_t body, size_t *plines)
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (plines)
*plines = mum->body_lines;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
......@@ -997,10 +992,8 @@ mbox_msg_received (message_t msg, char *buf, size_t len,
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
status = stream_readline (mum->stream, buffer, sizeof(buffer),
mum->header_from, &n);
mailbox_unlock (mum->mud->mailbox);
if (status != 0)
{
if (pnwrite)
......@@ -1043,10 +1036,8 @@ mbox_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
status = stream_readline (mum->stream, buffer, sizeof(buffer),
mum->header_from, &n);
mailbox_unlock (mum->mud->mailbox);
if (status != 0)
{
if (pnwrite)
......@@ -1188,8 +1179,13 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_append_message (%s)\n",
mud->name);
mailbox_wrlock (mailbox);
mbox_lock (mailbox, MU_LOCKER_WRLOCK);
monitor_wrlock (mailbox->monitor);
#ifdef WITH_PTHREAD
/* write()/read() are cancellation points. Since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
#endif
locker_lock (mailbox->locker, MU_LOCKER_WRLOCK);
{
off_t size;
int status;
......@@ -1200,8 +1196,8 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
status = stream_size (mailbox->stream, &size);
if (status != 0)
{
mailbox_unlock (mailbox);
mbox_unlock (mailbox);
locker_unlock (mailbox->locker);
monitor_unlock (mailbox->monitor);
return status;
}
......@@ -1211,8 +1207,8 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
mud->from = calloc (128, sizeof (char));
if (mud->from == NULL)
{
mbox_unlock (mailbox);
mailbox_unlock (mailbox);
locker_unlock (mailbox->locker);
monitor_unlock (mailbox->monitor);
return ENOMEM;
}
mud->date = calloc (128, sizeof (char));
......@@ -1221,8 +1217,8 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
free (mud->from);
mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
mailbox_unlock (mailbox);
locker_unlock (mailbox->locker);
monitor_unlock (mailbox->monitor);
return ENOMEM;
}
mud->off = 0;
......@@ -1242,9 +1238,9 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
free (mud->date);
mud->date = mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
locker_unlock (mailbox->locker);
}
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return status;
}
/* Nuke trailing newline. */
......@@ -1268,9 +1264,9 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
free (mud->date);
mud->date = mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
locker_unlock (mailbox->locker);
}
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return status;
}
/* Nuke trailing newline. */
......@@ -1313,10 +1309,10 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
free (mud->date);
mud->date = mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
locker_unlock (mailbox->locker);
}
stream_flush (mailbox->stream);
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return status;
}
stream_write (mailbox->stream, buffer, nread, size, &n);
......@@ -1333,8 +1329,11 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
}
stream_flush (mailbox->stream);
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
mailbox_unlock (mailbox);
locker_unlock (mailbox->locker);
monitor_unlock (mailbox->monitor);
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
return 0;
}
......@@ -1345,9 +1344,7 @@ mbox_size (mailbox_t mailbox, off_t *psize)
int status;
/* Maybe was not open yet ?? */
mailbox_rdlock (mailbox);
status = stream_size (mailbox->stream, &size);
mailbox_unlock (mailbox);
if (status != 0)
return status;
if (psize)
......@@ -1371,36 +1368,10 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount)
return 0;
}
/* Locking. */
static int
mbox_lock (mailbox_t mailbox, int flag)
{
if (mailbox && mailbox->locker != NULL)
{
locker_t locker = mailbox->locker;
locker_lock (locker, flag);
}
return 0;
}
static int
mbox_touchlock (mailbox_t mailbox)
{
if (mailbox && mailbox->locker != NULL)
{
locker_t locker = mailbox->locker;
locker_touchlock (locker);
}
return 0;
}
static int
mbox_unlock (mailbox_t mailbox)
static void
mbox_cleanup (void *arg)
{
if (mailbox && mailbox->locker != NULL)
{
locker_t locker = mailbox->locker;
locker_unlock (locker);
}
return 0;
mailbox_t mailbox = arg;
monitor_unlock (mailbox->monitor);
locker_unlock (mailbox->locker);
}
......
......@@ -191,17 +191,17 @@ do \
do \
{ \
int bailing = 0; \
mailbox_unlock (mbox); \
monitor_unlock (mbox->monitor); \
if (mbox->observable) \
bailing = observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mbox_unlock (mbox); \
locker_unlock (mbox->locker); \
return EINTR; \
} \
mailbox_wrlock (mbox); \
monitor_wrlock (mbox->monitor); \
} while (0);
/* Notification MBX_PROGRESS
......@@ -215,7 +215,7 @@ do \
{ \
{ \
int bailing = 0; \
mailbox_unlock (mbox); \
monitor_unlock (mbox->monitor); \
mud->messages_count--; \
if (mbox->observable) \
bailing = observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS); \
......@@ -223,11 +223,11 @@ do \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mbox_unlock (mbox); \
locker_unlock (mbox->locker); \
return EINTR; \
} \
mud->messages_count++; \
mailbox_wrlock (mbox); \
monitor_wrlock (mbox->monitor); \
} \
} while (0)
......@@ -243,16 +243,16 @@ do \
m = realloc ((mud)->umessages, num * sizeof (*m)); \
if (m == NULL) \
{ \
mbox_unlock (mbox); \
mailbox_unlock (mbox); \
locker_unlock (mbox->locker); \
monitor_unlock (mbox->monitor); \
return ENOMEM; \
} \
(mud)->umessages = m; \
(mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \
if ((mud)->umessages[num - 1] == NULL) \
{ \
mbox_unlock (mbox); \
mailbox_unlock (mbox); \
locker_unlock (mbox->locker); \
monitor_unlock (mbox->monitor); \
return ENOMEM; \
} \
(mud)->umessages_count = num; \
......@@ -282,17 +282,23 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
return EINVAL;
/* Grab the lock. */
mailbox_wrlock (mailbox);
monitor_wrlock (mailbox->monitor);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
#endif
/* Save the timestamp and size. */
status = stream_size (mailbox->stream, &(mud->size));
if (status != 0)
{
mailbox_unlock (mailbox);
monitor_unlock (mailbox->monitor);
return status;
}
mbox_lock (mailbox, MU_LOCKER_RDLOCK);
locker_lock (mailbox->locker, MU_LOCKER_RDLOCK);
/* Seek to the starting point. */
if (mud->umessages && msgno > 0 && mud->messages_count > 0
......@@ -376,7 +382,7 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
/* Every 50 mesgs update the lock, it should be every minute. */
if ((mud->messages_count % 50) == 0)
mbox_touchlock (mailbox);
locker_touchlock (mailbox->locker);
/* Ping them every 1000 lines. */
if (do_notif)
......@@ -392,9 +398,13 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
if (do_notif)
DISPATCH_ADD_MSG(mailbox, mud);
}
mbox_unlock (mailbox);
if (pcount)
*pcount = mud->messages_count;
mailbox_unlock (mailbox);
locker_unlock (mailbox->locker);
monitor_unlock (mailbox->monitor);
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
return status;
}
......
......@@ -189,7 +189,7 @@ struct _pop_data
#define CHECK_BUSY(mbox, mpd, function, identity) \
do \
{ \
int err = mailbox_wrlock (mbox); \
int err = monitor_wrlock (mbox->monitor); \
if (err != 0) \
return err; \
if ((mpd->func && mpd->func != function) \
......@@ -198,7 +198,7 @@ do \
mpd->id = 0; \
mpd->func = pop_open; \
mpd->state = POP_NO_STATE; \
mailbox_unlock (mbox); \
monitor_unlock (mbox->monitor); \
err = pop_open (mbox, mbox->flags); \
if (err != 0) \
{ \
......@@ -209,7 +209,7 @@ do \
{ \
mpd->id = (size_t)identity; \
mpd->func = func; \
mailbox_unlock (mbox); \
monitor_unlock (mbox->monitor); \
} \
} \
while (0)
......@@ -301,7 +301,7 @@ pop_destroy (mailbox_t mbox)
{
pop_data_t mpd = mbox->data;
size_t i;
mailbox_wrlock (mbox);
monitor_wrlock (mbox->monitor);
/* Destroy the pop messages and ressources associated to them. */
for (i = 0; i < mpd->pmessages_count; i++)
{
......@@ -320,7 +320,7 @@ pop_destroy (mailbox_t mbox)
free (mpd->pmessages);
free (mpd);
mbox->data = NULL;
mailbox_unlock (mbox);
monitor_unlock (mbox->monitor);
}
}
......@@ -545,12 +545,12 @@ pop_close (mailbox_t mbox)
return EINVAL;
/* CHECK_BUSY (mbox, mpd, func, 0); */
mailbox_wrlock (mbox);
monitor_wrlock (mbox->monitor);
if (mpd->func && mpd->func != func)
mpd->state = POP_NO_STATE;
mpd->id = 0;
mpd->func = func;
mailbox_unlock (mbox);
monitor_unlock (mbox->monitor);
/* Ok boys, it's a wrap: UPDATE State. */
switch (mpd->state)
......@@ -625,7 +625,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
if (pmsg == NULL || mpd == NULL)
return EINVAL;
mailbox_rdlock (mbox);
monitor_rdlock (mbox->monitor);
/* See if we have already this message. */
for (i = 0; i < mpd->pmessages_count; i++)
{
......@@ -634,12 +634,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
if (mpd->pmessages[i]->num == msgno)
{
*pmsg = mpd->pmessages[i]->message;
mailbox_unlock (mbox);
monitor_unlock (mbox->monitor);
return 0;
}
}
}
mailbox_unlock (mbox);
monitor_unlock (mbox->monitor);
mpm = calloc (1, sizeof (*mpm));
if (mpm == NULL)
......@@ -724,7 +724,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
message_set_uidl (msg, pop_uidl, mpm);
/* Add it to the list. */
mailbox_wrlock (mbox);
monitor_wrlock (mbox->monitor);
{
pop_message_t *m ;
m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
......@@ -732,14 +732,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
message_destroy (&msg, mpm);
free (mpm);
mailbox_unlock (mbox);
monitor_unlock (mbox->monitor);
return ENOMEM;
}
mpd->pmessages = m;
mpd->pmessages[mpd->pmessages_count] = mpm;
mpd->pmessages_count++;
}
mailbox_unlock (mbox);
monitor_unlock (mbox->monitor);
/* Save The message. */
*pmsg = mpm->message = msg;
......
......@@ -21,6 +21,8 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <time.h>
#include <mailutils/message.h>
#include <mailutils/stream.h>
......@@ -463,9 +465,9 @@ static int _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off,
return 0;
message_get_stream(mime->mtp_parts[mime->cur_part]->msg, &msg_stream);
} else {
body_t body;
message_get_body(mime->mtp_parts[mime->cur_part]->msg, &body);
body_get_stream(body, &msg_stream);
body_t b;
message_get_body(mime->mtp_parts[mime->cur_part]->msg, &b);
body_get_stream(b, &msg_stream);
}
ret = stream_read(msg_stream, buf, buflen, mime->part_offset, &part_nbytes );
len += part_nbytes;
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <errno.h>
#include <stdlib.h>
#include <monitor0.h>
int
monitor_create (monitor_t *pmonitor, void *owner)
{
monitor_t monitor;
int status = 0;
if (pmonitor == NULL)
return EINVAL;
monitor = calloc (1, sizeof (*monitor));
if (monitor == NULL)
return ENOMEM;
monitor->owner = owner;
status = RWLOCK_INIT (&(monitor->lock), NULL);
if (status == 0)
{
free (monitor);
return status;
}
*pmonitor = monitor;
return status;
}
void *
monitor_get_owner (monitor_t monitor)
{
return (monitor == NULL) ? NULL : monitor->owner;
}
void
monitor_destroy (monitor_t *pmonitor, void *owner)
{
if (pmonitor && *pmonitor)
{
monitor_t monitor = *pmonitor;
if (monitor->owner == owner)
{
RWLOCK_DESTROY (&(monitor->lock));
}
free (monitor);
*pmonitor = NULL;
}
}
int
monitor_rdlock (monitor_t monitor)
{
if (monitor)
{
return RWLOCK_RDLOCK (&(monitor->lock));
}
return 0;
}
int
monitor_wrlock (monitor_t monitor)
{
if (monitor)
{
return RWLOCK_WRLOCK (&(monitor->lock));
}
return 0;
}
int
monitor_unlock (monitor_t monitor)
{
if (monitor)
{
return RWLOCK_UNLOCK (&(monitor->lock));
}
return 0;
}
int
monitor_wait (monitor_t monitor)
{
(void)monitor;
return ENOSYS;
}
int
monitor_notify (monitor_t monitor)
{
(void)monitor;
return ENOSYS;
}