Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 2b88074b in mainline


Ignore:
Timestamp:
2009-10-29T22:06:46Z (11 years ago)
Author:
Martin Decky <martin@…>
Branches:
master
Children:
2e983c7
Parents:
14ecd6c
Message:

vfs: file descriptors housekeeping changes

  • add support for allocating new file descriptors from the end of the fd range (O_DESC)
  • add support for assigning of an already opened file to a free file descriptor

vfs: VFS_OUT_CLOSE is called only when the file reference count is about to drop to zero
vfs: implement VFS_IN_DUP

libc: optimize current working directory housekeeping

  • using opendir() was an overkill
  • allocate current working directory file descriptor from the end of the fd range using O_DESC (so it doesn't mess with the well-known descriptors 0, 1 and 2)

libc: implement dup2() (via VFS_IN_DUP)

getvc: change stdin/stdout/stderr by a slightly more elegant way (using dup2())

Location:
uspace
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/getvc/getvc.c

    r14ecd6c r2b88074b  
    3636
    3737#include <sys/types.h>
     38#include <fcntl.h>
    3839#include <unistd.h>
    3940#include <stdio.h>
     
    4647}
    4748
    48 static void closeall(void)
     49static void reopen(FILE **stream, int fd, const char *path, int flags, const char *mode)
    4950{
    50         fclose(stdin);
    51         fclose(stdout);
    52         fclose(stderr);
     51        if (fclose(*stream))
     52                return;
    5353       
    54         close(0);
    55         close(1);
    56         close(2);
     54        *stream = NULL;
     55       
     56        int oldfd = open(path, flags);
     57        if (oldfd < 0)
     58                return;
     59       
     60        if (oldfd != fd) {
     61                if (dup2(oldfd, fd) != fd)
     62                        return;
     63               
     64                if (close(oldfd))
     65                        return;
     66        }
     67       
     68        *stream = fdopen(fd, mode);
    5769}
    5870
     
    7486int main(int argc, char *argv[])
    7587{
    76         task_exit_t texit;
    77         int retval;
    78 
    7988        if (argc < 3) {
    8089                usage();
     
    8291        }
    8392       
    84         closeall();
     93        reopen(&stdin, 0, argv[1], O_RDONLY, "r");
     94        reopen(&stdout, 1, argv[1], O_WRONLY, "w");
     95        reopen(&stderr, 2, argv[1], O_WRONLY, "w");
    8596       
    86         stdin = fopen(argv[1], "r");
    87         stdout = fopen(argv[1], "w");
    88         stderr = fopen(argv[1], "w");
    89 
    9097        /*
    91          * FIXME: fopen() should actually detect that we are opening a console
     98         * FIXME: fdopen() should actually detect that we are opening a console
    9299         * and it should set line-buffering mode automatically.
    93100         */
    94101        setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
    95102       
    96         if ((stdin == NULL)
    97             || (stdout == NULL)
    98             || (stderr == NULL))
     103        if (stdin == NULL)
    99104                return -2;
     105       
     106        if (stdout == NULL)
     107                return -3;
     108       
     109        if (stderr == NULL)
     110                return -4;
    100111       
    101112        version_print(argv[1]);
    102113        task_id_t id = spawn(argv[2]);
     114       
     115        task_exit_t texit;
     116        int retval;
    103117        task_wait(id, &texit, &retval);
    104118       
  • uspace/lib/libc/generic/vfs/vfs.c

    r14ecd6c r2b88074b  
    5757static futex_t cwd_futex = FUTEX_INITIALIZER;
    5858
    59 DIR *cwd_dir = NULL;
    60 char *cwd_path = NULL;
    61 size_t cwd_size = 0;
     59static int cwd_fd = -1;
     60static char *cwd_path = NULL;
     61static size_t cwd_size = 0;
    6262
    6363char *absolutize(const char *path, size_t *retlen)
     
    197197}
    198198
    199 static int _open(const char *path, int lflag, int oflag, ...)
    200 {
    201         ipcarg_t rc;
     199static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
     200{
     201        futex_down(&vfs_phone_futex);
     202        async_serialize_start();
     203        vfs_connect();
     204       
    202205        ipc_call_t answer;
    203         aid_t req;
    204        
    205         size_t pa_size;
    206         char *pa = absolutize(path, &pa_size);
    207         if (!pa)
    208                 return ENOMEM;
    209        
    210         futex_down(&vfs_phone_futex);
    211         async_serialize_start();
    212         vfs_connect();
    213        
    214         req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer);
    215         rc = async_data_write_start(vfs_phone, pa, pa_size);
     206        aid_t req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer);
     207        ipcarg_t rc = async_data_write_start(vfs_phone, abs, abs_size);
     208       
    216209        if (rc != EOK) {
    217210                ipcarg_t rc_orig;
    218        
    219                 async_wait_for(req, &rc_orig);
    220                 async_serialize_end();
    221                 futex_up(&vfs_phone_futex);
    222                 free(pa);
    223                 if (rc_orig == EOK)
    224                         return (int) rc;
    225                 else
    226                         return (int) rc_orig;
    227         }
    228         async_wait_for(req, &rc);
    229         async_serialize_end();
    230         futex_up(&vfs_phone_futex);
    231         free(pa);
     211                async_wait_for(req, &rc_orig);
     212               
     213                async_serialize_end();
     214                futex_up(&vfs_phone_futex);
     215               
     216                if (rc_orig == EOK)
     217                        return (int) rc;
     218                else
     219                        return (int) rc_orig;
     220        }
     221       
     222        async_wait_for(req, &rc);
     223        async_serialize_end();
     224        futex_up(&vfs_phone_futex);
    232225       
    233226        if (rc != EOK)
     
    239232int open(const char *path, int oflag, ...)
    240233{
    241         return _open(path, L_FILE, oflag);
     234        size_t abs_size;
     235        char *abs = absolutize(path, &abs_size);
     236        if (!abs)
     237                return ENOMEM;
     238       
     239        int ret = open_internal(abs, abs_size, L_FILE, oflag);
     240        free(abs);
     241       
     242        return ret;
    242243}
    243244
     
    471472        if (!dirp)
    472473                return NULL;
    473         dirp->fd = _open(dirname, L_DIRECTORY, 0);
    474         if (dirp->fd < 0) {
     474       
     475        size_t abs_size;
     476        char *abs = absolutize(dirname, &abs_size);
     477        if (!abs) {
     478                free(dirp);
     479                return ENOMEM;
     480        }
     481       
     482        int ret = open_internal(abs, abs_size, L_DIRECTORY, 0);
     483        free(abs);
     484       
     485        if (ret < 0) {
    475486                free(dirp);
    476487                return NULL;
    477488        }
     489       
     490        dirp->fd = ret;
    478491        return dirp;
    479492}
     
    636649int chdir(const char *path)
    637650{
    638         size_t pa_size;
    639         char *pa = absolutize(path, &pa_size);
    640         if (!pa)
    641                 return ENOMEM;
    642 
    643         DIR *d = opendir(pa);
    644         if (!d) {
    645                 free(pa);
     651        size_t abs_size;
     652        char *abs = absolutize(path, &abs_size);
     653        if (!abs)
     654                return ENOMEM;
     655       
     656        int fd = open_internal(abs, abs_size, L_DIRECTORY, O_DESC);
     657       
     658        if (fd < 0) {
     659                free(abs);
    646660                return ENOENT;
    647661        }
    648 
     662       
    649663        futex_down(&cwd_futex);
    650         if (cwd_dir) {
    651                 closedir(cwd_dir);
    652                 cwd_dir = NULL;
    653                 free(cwd_path);
    654                 cwd_path = NULL;
    655                 cwd_size = 0;
    656         }
    657         cwd_dir = d;
    658         cwd_path = pa;
    659         cwd_size = pa_size;
     664       
     665        if (cwd_fd >= 0)
     666                close(cwd_fd);
     667       
     668       
     669        if (cwd_path)
     670                free(cwd_path);
     671       
     672        cwd_fd = fd;
     673        cwd_path = abs;
     674        cwd_size = abs_size;
     675       
    660676        futex_up(&cwd_futex);
    661677        return EOK;
     
    664680char *getcwd(char *buf, size_t size)
    665681{
    666         if (!cwd_size)
     682        if (size == 0)
    667683                return NULL;
    668         if (!size)
    669                 return NULL;
     684       
    670685        futex_down(&cwd_futex);
    671         if (size < cwd_size + 1) {
     686       
     687        if ((cwd_size == 0) || (size < cwd_size + 1)) {
    672688                futex_up(&cwd_futex);
    673689                return NULL;
    674690        }
     691       
    675692        str_cpy(buf, size, cwd_path);
    676693        futex_up(&cwd_futex);
     694       
    677695        return buf;
    678696}
     
    707725}
    708726
     727int dup2(int oldfd, int newfd)
     728{
     729        futex_down(&vfs_phone_futex);
     730        async_serialize_start();
     731        vfs_connect();
     732       
     733        ipcarg_t ret;
     734        ipcarg_t rc = async_req_2_1(vfs_phone, VFS_IN_DUP, oldfd, newfd, &ret);
     735       
     736        async_serialize_end();
     737        futex_up(&vfs_phone_futex);
     738       
     739        if (rc == EOK)
     740                return (int) ret;
     741       
     742        return (int) rc;
     743}
     744
    709745/** @}
    710746 */
  • uspace/lib/libc/include/fcntl.h

    r14ecd6c r2b88074b  
    4343#define O_RDWR    32
    4444#define O_WRONLY  64
     45#define O_DESC    128
    4546
    4647extern int open(const char *, int, ...);
  • uspace/lib/libc/include/ipc/vfs.h

    r14ecd6c r2b88074b  
    7373        VFS_IN_UNLINK,
    7474        VFS_IN_RENAME,
    75         VFS_IN_STAT
     75        VFS_IN_STAT,
     76        VFS_IN_DUP
    7677} vfs_in_request_t;
    7778
  • uspace/lib/libc/include/unistd.h

    r14ecd6c r2b88074b  
    5151#endif
    5252
     53extern int dup2(int oldfd, int newfd);
     54
    5355extern ssize_t write(int, const void *, size_t);
    5456extern ssize_t read(int, void *, size_t);
  • uspace/srv/vfs/vfs.c

    r14ecd6c r2b88074b  
    126126                        vfs_sync(callid, &call);
    127127                        break;
     128                case VFS_IN_DUP:
     129                        vfs_dup(callid, &call);
    128130                default:
    129131                        ipc_answer_0(callid, ENOTSUP);
  • uspace/srv/vfs/vfs.h

    r14ecd6c r2b88074b  
    186186extern bool vfs_files_init(void);
    187187extern vfs_file_t *vfs_file_get(int);
    188 extern int vfs_fd_alloc(void);
     188extern int vfs_fd_assign(vfs_file_t *file, int fd);
     189extern int vfs_fd_alloc(bool desc);
    189190extern int vfs_fd_free(int);
    190191
     
    200201extern void vfs_open_node(ipc_callid_t, ipc_call_t *);
    201202extern void vfs_sync(ipc_callid_t, ipc_call_t *);
     203extern void vfs_dup(ipc_callid_t, ipc_call_t *);
    202204extern void vfs_close(ipc_callid_t, ipc_call_t *);
    203205extern void vfs_read(ipc_callid_t, ipc_call_t *);
  • uspace/srv/vfs/vfs_file.c

    r14ecd6c r2b88074b  
    7676/** Allocate a file descriptor.
    7777 *
    78  * @return              First available file descriptor or a negative error
    79  *                      code.
    80  */
    81 int vfs_fd_alloc(void)
     78 * @param desc If true, look for an available file descriptor
     79 *             in a descending order.
     80 *
     81 * @return First available file descriptor or a negative error
     82 *         code.
     83 */
     84int vfs_fd_alloc(bool desc)
    8285{
    8386        if (!vfs_files_init())
     
    8588       
    8689        unsigned int i;
    87         for (i = 0; i < MAX_OPEN_FILES; i++) {
     90        if (desc)
     91                i = MAX_OPEN_FILES;
     92        else
     93                i = 0;
     94       
     95        while (true) {
    8896                if (!files[i]) {
    8997                        files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
     
    96104                        return (int) i;
    97105                }
     106               
     107                if (desc) {
     108                        if (i == 0)
     109                                break;
     110                       
     111                        i--;
     112                } else {
     113                        if (i == MAX_OPEN_FILES)
     114                                break;
     115                       
     116                        i++;
     117                }
    98118        }
    99119       
     
    118138        vfs_file_delref(files[fd]);
    119139        files[fd] = NULL;
     140       
     141        return EOK;
     142}
     143
     144/** Assign a file to a file descriptor.
     145 *
     146 * @param file File to assign.
     147 * @param fd   File descriptor to assign to.
     148 *
     149 * @return EOK on success or EINVAL if fd is an invalid or already
     150 *         used file descriptor.
     151 *
     152 */
     153int vfs_fd_assign(vfs_file_t *file, int fd)
     154{
     155        if (!vfs_files_init())
     156                return ENOMEM;
     157       
     158        if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] != NULL))
     159                return EINVAL;
     160       
     161        files[fd] = file;
     162        vfs_file_addref(files[fd]);
    120163       
    121164        return EOK;
  • uspace/srv/vfs/vfs_ops.c

    r14ecd6c r2b88074b  
    543543         * structure.
    544544         */
    545         int fd = vfs_fd_alloc();
     545        int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
    546546        if (fd < 0) {
    547547                vfs_node_put(node);
     
    620620         * structure.
    621621         */
    622         int fd = vfs_fd_alloc();
     622        int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
    623623        if (fd < 0) {
    624624                vfs_node_put(node);
     
    679679}
    680680
     681static int vfs_close_internal(vfs_file_t *file)
     682{
     683        /*
     684         * Lock the open file structure so that no other thread can manipulate
     685         * the same open file at a time.
     686         */
     687        fibril_mutex_lock(&file->lock);
     688       
     689        if (file->refcnt <= 1) {
     690                /* Only close the file on the destination FS server
     691                   if there are no more file descriptors (except the
     692                   present one) pointing to this file. */
     693               
     694                int fs_phone = vfs_grab_phone(file->node->fs_handle);
     695               
     696                /* Make a VFS_OUT_CLOSE request at the destination FS server. */
     697                aid_t msg;
     698                ipc_call_t answer;
     699                msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
     700                    file->node->index, &answer);
     701               
     702                /* Wait for reply from the FS server. */
     703                ipcarg_t rc;
     704                async_wait_for(msg, &rc);
     705               
     706                vfs_release_phone(fs_phone);
     707                fibril_mutex_unlock(&file->lock);
     708               
     709                return IPC_GET_ARG1(answer);
     710        }
     711       
     712        fibril_mutex_unlock(&file->lock);
     713        return EOK;
     714}
     715
    681716void vfs_close(ipc_callid_t rid, ipc_call_t *request)
    682717{
     
    690725        }
    691726       
    692         /*
    693          * Lock the open file structure so that no other thread can manipulate
    694          * the same open file at a time.
    695          */
    696         fibril_mutex_lock(&file->lock);
    697         int fs_phone = vfs_grab_phone(file->node->fs_handle);
    698        
    699         /* Make a VFS_OUT_CLOSE request at the destination FS server. */
    700         aid_t msg;
    701         ipc_call_t answer;
    702         msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
    703             file->node->index, &answer);
    704 
    705         /* Wait for reply from the FS server. */
    706         ipcarg_t rc;
    707         async_wait_for(msg, &rc);
    708 
    709         vfs_release_phone(fs_phone);
    710         fibril_mutex_unlock(&file->lock);
    711        
    712         int retval = IPC_GET_ARG1(answer);
    713         if (retval != EOK)
    714                 ipc_answer_0(rid, retval);
    715        
    716         retval = vfs_fd_free(fd);
    717         ipc_answer_0(rid, retval);
     727        int ret = vfs_close_internal(file);
     728        if (ret != EOK)
     729                ipc_answer_0(rid, ret);
     730       
     731        ret = vfs_fd_free(fd);
     732        ipc_answer_0(rid, ret);
    718733}
    719734
     
    13101325}
    13111326
     1327void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
     1328{
     1329        int oldfd = IPC_GET_ARG1(*request);
     1330        int newfd = IPC_GET_ARG2(*request);
     1331       
     1332        /* Lookup the file structure corresponding to oldfd. */
     1333        vfs_file_t *oldfile = vfs_file_get(oldfd);
     1334        if (!oldfile) {
     1335                ipc_answer_0(rid, EBADF);
     1336                return;
     1337        }
     1338       
     1339        /* If the file descriptors are the same, do nothing. */
     1340        if (oldfd == newfd) {
     1341                ipc_answer_1(rid, EOK, newfd);
     1342                return;
     1343        }
     1344       
     1345        /*
     1346         * Lock the open file structure so that no other thread can manipulate
     1347         * the same open file at a time.
     1348         */
     1349        fibril_mutex_lock(&oldfile->lock);
     1350       
     1351        /* Lookup an open file structure possibly corresponding to newfd. */
     1352        vfs_file_t *newfile = vfs_file_get(newfd);
     1353        if (newfile) {
     1354                /* Close the originally opened file. */
     1355                int ret = vfs_close_internal(newfile);
     1356                if (ret != EOK) {
     1357                        ipc_answer_0(rid, ret);
     1358                        return;
     1359                }
     1360               
     1361                ret = vfs_fd_free(newfd);
     1362                if (ret != EOK) {
     1363                        ipc_answer_0(rid, ret);
     1364                        return;
     1365                }
     1366        }
     1367       
     1368        /* Assign the old file to newfd. */
     1369        int ret = vfs_fd_assign(oldfile, newfd);
     1370        fibril_mutex_unlock(&oldfile->lock);
     1371       
     1372        if (ret != EOK)
     1373                ipc_answer_0(rid, ret);
     1374        else
     1375                ipc_answer_1(rid, EOK, newfd);
     1376}
     1377
    13121378/**
    13131379 * @}
Note: See TracChangeset for help on using the changeset viewer.