+2004-08-27 Ken Raeburn <raeburn@mit.edu>
+
+ * prof_int.h (struct _prf_data_t): Add a mutex.
+ * prof_file.c (profile_open_file): Initialize data mutex.
+ (profile_update_file_data, profile_flush_file_data): Lock it while
+ manipulating file data.
+ (profile_lock_global, profile_unlock_global): New functions.
+ * prof_set.c (rw_setup): Acquire global lock while checking flags
+ and adjusting ref count.
+ (profile_update_relation, profile_rename_section,
+ profile_add_relation): Lock data mutex while manipulating profile
+ data.
+ * prof_tree.c (profile_node_iterator): Do more magic number
+ tests.
+
2004-07-14 Ken Raeburn <raeburn@mit.edu>
* libprofile.exports: Don't try to export
data->comment = 0;
data->filespec = expanded_filename;
+ retval = k5_mutex_init(&data->lock);
+ if (retval) {
+ profile_close_file(prf);
+ return retval;
+ }
+
retval = profile_update_file(prf);
if (retval) {
+ k5_mutex_destroy(&data->lock);
profile_close_file(prf);
return retval;
}
#endif
FILE *f;
+ retval = k5_mutex_lock(&data->lock);
+ if (retval)
+ return retval;
+
#ifdef HAVE_STAT
- if (stat(data->filespec, &st))
- return errno;
- if (st.st_mtime == data->timestamp)
- return 0;
+ if (stat(data->filespec, &st)) {
+ retval = errno;
+ k5_mutex_unlock(&data->lock);
+ return retval;
+ }
+ if (st.st_mtime == data->timestamp) {
+ k5_mutex_unlock(&data->lock);
+ return 0;
+ }
if (data->root) {
profile_free_node(data->root);
data->root = 0;
* memory image is correct. That is, we won't reread the
* profile file if it changes.
*/
- if (data->root)
- return 0;
+ if (data->root) {
+ k5_mutex_unlock(&data->lock);
+ return 0;
+ }
#endif
errno = 0;
f = fopen(data->filespec, "r");
if (f == NULL) {
retval = errno;
+ k5_mutex_unlock(&data->lock);
if (retval == 0)
retval = ENOENT;
return retval;
data->flags |= PROFILE_FILE_RW;
retval = profile_parse_file(f, &data->root);
fclose(f);
- if (retval)
- return retval;
+ if (retval) {
+ k5_mutex_unlock(&data->lock);
+ return retval;
+ }
#ifdef HAVE_STAT
data->timestamp = st.st_mtime;
#endif
+ k5_mutex_unlock(&data->lock);
return 0;
}
profile_filespec_t new_file;
profile_filespec_t old_file;
errcode_t retval = 0;
-
+
if (!data || data->magic != PROF_MAGIC_FILE_DATA)
return PROF_MAGIC_FILE_DATA;
+
+ retval = k5_mutex_lock(&data->lock);
+ if (retval)
+ return retval;
- if ((data->flags & PROFILE_FILE_DIRTY) == 0)
- return 0;
+ if ((data->flags & PROFILE_FILE_DIRTY) == 0) {
+ k5_mutex_unlock(&data->lock);
+ return 0;
+ }
retval = ENOMEM;
retval = 0;
errout:
+ k5_mutex_unlock(&data->lock);
if (new_file)
free(new_file);
if (old_file)
#endif
}
+int profile_lock_global()
+{
+ return k5_mutex_lock(&g_shared_trees_mutex);
+}
+int profile_unlock_global()
+{
+ return k5_mutex_unlock(&g_shared_trees_mutex);
+}
+
void profile_free_file(prf_file_t prf)
{
profile_dereference_data(prf->data);
#define PROFILE_SUPPORTS_FOREIGN_NEWLINES
#endif
+/* N.B.: The locking code for the non-sharing case is not complete.
+ Be sure to fix it if you turn off this flag. */
#define SHARE_TREE_DATA
#include "k5-thread.h"
/*
* This is the structure which stores the profile information for a
* particular configuration file.
+ *
+ * Locking strategy:
+ * - filespec is fixed after creation
+ * - refcount and next should only be tweaked with the global lock held
+ * - other fields can be tweaked after grabbing the in-struct lock
*/
struct _prf_data_t {
prf_magic_t magic;
+ k5_mutex_t lock;
char *comment;
profile_filespec_t filespec;
struct profile_node *root;
return PROF_MAGIC_PROFILE;
file = profile->first_file;
+
if (!(file->data->flags & PROFILE_FILE_RW))
- return PROF_READ_ONLY;
+ return PROF_READ_ONLY;
+
+ retval = profile_lock_global();
+ if (retval)
+ return retval;
/* Don't update the file if we've already made modifications */
- if (file->data->flags & PROFILE_FILE_DIRTY)
- return 0;
+ if (file->data->flags & PROFILE_FILE_DIRTY) {
+ profile_unlock_global();
+ return 0;
+ }
#ifdef SHARE_TREE_DATA
if ((file->data->flags & PROFILE_FILE_SHARED) != 0) {
}
if (retval != 0) {
+ profile_unlock_global();
free(new_data);
return retval;
}
}
#endif /* SHARE_TREE_DATA */
+ profile_unlock_global();
retval = profile_update_file(file);
return retval;
if (!old_value || !*old_value)
return PROF_EINVAL;
+ retval = k5_mutex_lock(&profile->first_file->data->lock);
+ if (retval)
+ return retval;
section = profile->first_file->data->root;
for (cpp = names; cpp[1]; cpp++) {
state = 0;
retval = profile_find_node(section, *cpp, 0, 1,
&state, §ion);
- if (retval)
- return retval;
+ if (retval) {
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return retval;
+ }
}
state = 0;
retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
- if (retval)
- return retval;
-
- if (new_value)
+ if (retval == 0) {
+ if (new_value)
retval = profile_set_relation_value(node, new_value);
- else
+ else
retval = profile_remove_node(node);
- if (retval)
- return retval;
-
- profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+ }
+ if (retval == 0)
+ profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+ k5_mutex_unlock(&profile->first_file->data->lock);
- return 0;
+ return retval;
}
/*
struct profile_node *section, *node;
void *state;
const char **cpp;
-
+
retval = rw_setup(profile);
if (retval)
return retval;
if (names == 0 || names[0] == 0 || names[1] == 0)
return PROF_BAD_NAMESET;
+ retval = k5_mutex_lock(&profile->first_file->data->lock);
+ if (retval)
+ return retval;
section = profile->first_file->data->root;
for (cpp = names; cpp[1]; cpp++) {
state = 0;
retval = profile_find_node(section, *cpp, 0, 1,
&state, §ion);
- if (retval)
- return retval;
+ if (retval) {
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return retval;
+ }
}
state = 0;
retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
- if (retval)
- return retval;
-
- if (new_name)
+ if (retval == 0) {
+ if (new_name)
retval = profile_rename_node(node, new_name);
- else
+ else
retval = profile_remove_node(node);
- if (retval)
- return retval;
-
- profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
-
- return 0;
+ }
+ if (retval == 0)
+ profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return retval;
}
/*
if (names == 0 || names[0] == 0 || names[1] == 0)
return PROF_BAD_NAMESET;
+ retval = k5_mutex_lock(&profile->first_file->data->lock);
+ if (retval)
+ return retval;
section = profile->first_file->data->root;
for (cpp = names; cpp[1]; cpp++) {
state = 0;
&state, §ion);
if (retval == PROF_NO_SECTION)
retval = profile_add_node(section, *cpp, 0, §ion);
- if (retval)
- return retval;
+ if (retval) {
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return retval;
+ }
}
if (new_value == 0) {
retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
- if (retval == 0)
- return PROF_EXISTS;
- else if (retval != PROF_NO_SECTION)
- return retval;
+ if (retval == 0) {
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return PROF_EXISTS;
+ } else if (retval != PROF_NO_SECTION) {
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return retval;
+ }
}
retval = profile_add_node(section, *cpp, new_value, 0);
- if (retval)
- return retval;
+ if (retval) {
+ k5_mutex_unlock(&profile->first_file->data->lock);
+ return retval;
+ }
profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
-
+ k5_mutex_unlock(&profile->first_file->data->lock);
return 0;
}
if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
return PROF_MAGIC_ITERATOR;
+ if (iter->file && iter->file->magic != PROF_MAGIC_FILE)
+ return PROF_MAGIC_FILE;
+ if (iter->file && iter->file->data->magic != PROF_MAGIC_FILE_DATA)
+ return PROF_MAGIC_FILE_DATA;
/*
* If the file has changed, then the node pointer is invalid,
* so we'll have search the file again looking for it.
skip_num = iter->num;
iter->node = 0;
}
+ if (iter->node && iter->node->magic != PROF_MAGIC_NODE)
+ return PROF_MAGIC_NODE;
get_new_file:
if (iter->node == 0) {
if (iter->file == 0 ||
*/
section = iter->file->data->root;
for (cpp = iter->names; cpp[iter->done_idx]; cpp++) {
- for (p=section->first_child; p; p = p->next)
+ for (p=section->first_child; p; p = p->next) {
if (!strcmp(p->name, *cpp) && !p->value)
break;
+ }
if (!p) {
section = 0;
break;