Craig Rodrigues wrote: > On Mon, Jan 06, 2003 at 01:55:24PM -0500, Garrett Wollman wrote: > > (We really should figure out how to implement the _r functions, > > because a POSIX.1-2001 system with threads is supposed to have them.) > > How do these functions need to be implemented? Is it sufficient > to re-implement the non-reentrant versions of these functions, > but avoid using static data variables? Or does there need > to be some use of thread mutexes within the function itself?
The pointers in the returned struct passwd already point to read-only data areas, so it's not really an issue (they are strings in the areas mmap'ed out of the password file itself). You would need to pass a struct down, and fill it in, instead of returning a static struct with the pointer. Applications can occasionally change the contents of these areas (e.g. "cron"), assuming that they are application private. If a threaded application were to do the same thing, and assume the data areas were thread-private, then it would need to copy the data pointed to by the pointers. Technically, this isn't a legal thing for the application to do; a modification should be made to ensure the mmap() is actually done read-only, so that a fault will occur if such access is attempted (and then someone will need to fix cron). The negative part of this is that you can not destruct the returned struct passwd, and automatically destruct the strings, too: because the areas are pointers to strings, rather than character arrays (as they were in older implementations), unless these areas are treated as "shared, read-only" (per the previous paragraph), you will need an explicit destructor function, which will free the allocated regions pointed to by the pointer memberts of the structure. This is actually not as big a deal as it seems; you can, instead, overallocate the returned structure by the amount necessary to contain the strings and their NUL termination, too, instead. Then the structure may be freed, which will free the additional memory, as a desirable side effect (no destructor function needed), e.g.: struct passwd *rvp; char *p; lname = strlen(op->pw_name) + 1; lpasswd = strlen(op->pw_passwd) + 1; lclass = strlen(op->pw_class) + 1; lgecos = strlen(op->pw_gecos) + 1; ldir = strlen(op->pw_dir) + 1; lshell = strlen(op->pw_shell) + 1; rvp = (struct passwd *)malloc(sizeof(struct passwd) + lname + lpasswd + lclass + lgecos + ldir + lshell); if ( rvp != NULL) { memcpy(rvp, op, sizeof(struct passwd)); p = (char *)(rvp + 1); memcpy( p, op->pw_name, lname); rvp->pw_name = p; p += lname; ... } ... The other big issue is mostly for the iterator functions; the current offset used by getpwent/setpwent/setpassent/endpwent must also be passed to those functions; I don't believe setpassent is completely commonplace (it's a 4.3-RENO-ism), so there are no manual pages you can look up for it (you'll have to make something up). In that case, you will need to re-seek on each iteration before the read, and have to hold the lock over the seek/read pair. Probably you will have to eat the open/close overhead, too, unless you lock and maintain an open instance count, and only close on the 1->0 reference transition. -- Terry To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message