+2005-02-23 Ken Raeburn <raeburn@mit.edu>
+
+ * prof_tree.c (profile_node_iterator): Check that the root node
+ pointer is not null; raise assertion failure if it is.
+
+ * prof_int.h: Include k5-platform.h.
+ (struct _prf_data_t): Reorder fields, and insert some padding.
+
+ * prof_file.c (scan_shared_trees_locked): Check that the "root"
+ field isn't null.
+ (profile_open_file): Update the in-memory file contents after
+ updating the refcount instead of before.
+ (profile_update_file_data): If the root node in the file data is
+ null, always do the update. Check that it's not null before
+ returning a success indication.
+ (profile_dereference_data_locked): Scan linked list of file data
+ objects for sanity check, before and after.
+ (profile_dereference_data_locked): Don't do it here.
+
2005-01-13 Ken Raeburn <raeburn@mit.edu>
* prof_file.c (profile_free_file_data): Destroy mutex before
assert(d->fslen <= 1000); /* XXX */ \
assert(d->filespec[d->fslen] == 0); \
assert(d->fslen = strlen(d->filespec)); \
+ assert(d->root != NULL); \
} \
}
break;
}
if (data) {
- retval = profile_update_file_data(data);
data->refcount++;
(void) k5_mutex_unlock(&g_shared_trees_mutex);
+ retval = profile_update_file_data(data);
free(expanded_filename);
prf->data = data;
*ret_prof = prf;
#ifdef HAVE_STAT
#ifdef STAT_ONCE_PER_SECOND
now = time(0);
- if (now == data->last_stat) {
+ if (now == data->last_stat && data->root != NULL) {
k5_mutex_unlock(&data->lock);
return 0;
}
#ifdef STAT_ONCE_PER_SECOND
data->last_stat = now;
#endif
- if (st.st_mtime == data->timestamp) {
+ if (st.st_mtime == data->timestamp && data->root != NULL) {
k5_mutex_unlock(&data->lock);
return 0;
}
k5_mutex_unlock(&data->lock);
return retval;
}
+ assert(data->root != NULL);
#ifdef HAVE_STAT
data->timestamp = st.st_mtime;
#endif
void profile_dereference_data(prf_data_t data)
{
int err;
- scan_shared_trees_unlocked();
err = k5_mutex_lock(&g_shared_trees_mutex);
if (err)
return;
profile_dereference_data_locked(data);
(void) k5_mutex_unlock(&g_shared_trees_mutex);
- scan_shared_trees_unlocked();
}
void profile_dereference_data_locked(prf_data_t data)
{
+ scan_shared_trees_locked();
data->refcount--;
if (data->refcount == 0)
profile_free_file_data(data);
+ scan_shared_trees_locked();
}
int profile_lock_global()
#endif
#include "k5-thread.h"
+#include "k5-platform.h"
#include "com_err.h"
#include "profile.h"
* particular configuration file.
*
* Locking strategy:
- * - filespec is fixed after creation
+ * - filespec, fslen are 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;
struct profile_node *root;
#ifdef STAT_ONCE_PER_SECOND
time_t last_stat;
time_t timestamp; /* time tree was last updated from file */
int flags; /* r/w, dirty */
int upd_serial; /* incremented when data changes */
+ char *comment;
+
+ size_t fslen;
+
+ /* Some separation between fields controlled by different
+ mutexes. Theoretically, both could be accessed at the same
+ time from different threads on different CPUs with separate
+ caches. Don't let the threads clobber each other's
+ changes. One mutex controlling the whole thing would be
+ better, but sufficient separation might suffice.
+
+ This is icky. I just hope it's adequate.
+
+ For next major release, fix this. */
+ union { double d; void *p; UINT64_TYPE ll; k5_mutex_t m; } pad;
+
int refcount; /* prf_file_t references */
struct _prf_data_t *next;
/* Was: "profile_filespec_t filespec". Now: flexible char
array ... except, we need to work in C89, so an array
length must be specified. */
- size_t fslen;
const char filespec[sizeof("/etc/krb5.conf")];
};
* or find the containing section if not.
*/
section = iter->file->data->root;
+ assert(section != NULL);
for (cpp = iter->names; cpp[iter->done_idx]; cpp++) {
for (p=section->first_child; p; p = p->next) {
if (!strcmp(p->name, *cpp) && !p->value)