File indexing completed on 2025-05-11 08:24:28
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #ifdef HAVE_CONFIG_H
0027 #include "config.h"
0028 #endif
0029
0030 #include <sys/stat.h>
0031 #include <sys/ioctl.h>
0032 #include <sys/uio.h>
0033 #include <fcntl.h>
0034 #include <unistd.h>
0035 #include <errno.h>
0036
0037 #include <rtems/imfs.h>
0038 #include <rtems/malloc.h>
0039 #include <rtems/libcsupport.h>
0040
0041 #include <tmacros.h>
0042
0043 const char rtems_test_name[] = "FSCLOSE 1";
0044
0045 typedef enum {
0046 ACTION_CLOSE,
0047 ACTION_FCNTL,
0048 ACTION_FDATASYNC,
0049 ACTION_FCHDIR,
0050 ACTION_FCHMOD,
0051 ACTION_FCHOWN,
0052
0053 ACTION_FSTAT,
0054 ACTION_FSYNC,
0055 ACTION_FTRUNCATE,
0056 ACTION_IOCTL,
0057 ACTION_LSEEK,
0058 ACTION_READ,
0059 ACTION_READV,
0060 ACTION_WRITE,
0061 ACTION_WRITEV
0062 } test_action;
0063
0064 typedef struct {
0065 rtems_id worker_id;
0066 int fd;
0067 test_action action;
0068 bool wait_in_close;
0069 bool wait_in_fstat;
0070 int close_count;
0071 int fcntl_count;
0072 int fdatasync_count;
0073 int fstat_count;
0074 int fsync_count;
0075 int ftruncate_count;
0076 int ioctl_count;
0077 int lseek_count;
0078 int open_count;
0079 int read_count;
0080 int readv_count;
0081 int write_count;
0082 int writev_count;
0083 } test_context;
0084
0085 static test_context test_instance;
0086
0087 static void wait(void)
0088 {
0089 rtems_status_code sc;
0090
0091 sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0092 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0093 }
0094
0095 static void wakeup_worker(const test_context *ctx)
0096 {
0097 rtems_status_code sc;
0098
0099 sc = rtems_event_transient_send(ctx->worker_id);
0100 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0101 }
0102
0103 static int handler_open(
0104 rtems_libio_t *iop,
0105 const char *path,
0106 int oflag,
0107 mode_t mode
0108 )
0109 {
0110 test_context *ctx;
0111
0112 ctx = IMFS_generic_get_context_by_iop(iop);
0113 ++ctx->open_count;
0114
0115 return 0;
0116 }
0117
0118 static int handler_close(
0119 rtems_libio_t *iop
0120 )
0121 {
0122 test_context *ctx;
0123
0124 ctx = IMFS_generic_get_context_by_iop(iop);
0125 ++ctx->close_count;
0126
0127 if (ctx->wait_in_close) {
0128 ctx->wait_in_close = false;
0129 wait();
0130 }
0131
0132 return 0;
0133 }
0134
0135 static ssize_t handler_read(
0136 rtems_libio_t *iop,
0137 void *buffer,
0138 size_t count
0139 )
0140 {
0141 test_context *ctx;
0142
0143 ctx = IMFS_generic_get_context_by_iop(iop);
0144 ++ctx->read_count;
0145
0146 wait();
0147 return 0;
0148 }
0149
0150 static ssize_t handler_write(
0151 rtems_libio_t *iop,
0152 const void *buffer,
0153 size_t count
0154 )
0155 {
0156 test_context *ctx;
0157
0158 ctx = IMFS_generic_get_context_by_iop(iop);
0159 ++ctx->write_count;
0160
0161 wait();
0162 return 0;
0163 }
0164
0165 static int handler_ioctl(
0166 rtems_libio_t *iop,
0167 ioctl_command_t request,
0168 void *buffer
0169 )
0170 {
0171 test_context *ctx;
0172
0173 ctx = IMFS_generic_get_context_by_iop(iop);
0174 ++ctx->ioctl_count;
0175
0176 wait();
0177 return 0;
0178 }
0179
0180 static off_t handler_lseek(
0181 rtems_libio_t *iop,
0182 off_t length,
0183 int whence
0184 )
0185 {
0186 test_context *ctx;
0187
0188 ctx = IMFS_generic_get_context_by_iop(iop);
0189 ++ctx->lseek_count;
0190
0191 wait();
0192 return 0;
0193 }
0194
0195 static int handler_fstat(
0196 const rtems_filesystem_location_info_t *loc,
0197 struct stat *buf
0198 )
0199 {
0200 test_context *ctx;
0201
0202 buf->st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO;
0203 ctx = IMFS_generic_get_context_by_location(loc);
0204 ++ctx->fstat_count;
0205
0206 if (ctx->wait_in_fstat) {
0207 ctx->wait_in_fstat = false;
0208 wait();
0209 }
0210
0211 return 0;
0212 }
0213
0214 static int handler_ftruncate(
0215 rtems_libio_t *iop,
0216 off_t length
0217 )
0218 {
0219 test_context *ctx;
0220
0221 ctx = IMFS_generic_get_context_by_iop(iop);
0222 ++ctx->ftruncate_count;
0223
0224 wait();
0225 return 0;
0226 }
0227
0228 static int handler_fsync(
0229 rtems_libio_t *iop
0230 )
0231 {
0232 test_context *ctx;
0233
0234 ctx = IMFS_generic_get_context_by_iop(iop);
0235 ++ctx->fsync_count;
0236
0237 wait();
0238 return 0;
0239 }
0240
0241 static int handler_fdatasync(
0242 rtems_libio_t *iop
0243 )
0244 {
0245 test_context *ctx;
0246
0247 ctx = IMFS_generic_get_context_by_iop(iop);
0248 ++ctx->fdatasync_count;
0249
0250 wait();
0251 return 0;
0252 }
0253
0254 static int handler_fcntl(
0255 rtems_libio_t *iop,
0256 int cmd
0257 )
0258 {
0259 test_context *ctx;
0260
0261 ctx = IMFS_generic_get_context_by_iop(iop);
0262 ++ctx->fcntl_count;
0263
0264 wait();
0265 return 0;
0266 }
0267
0268 static ssize_t handler_readv(
0269 rtems_libio_t *iop,
0270 const struct iovec *iov,
0271 int iovcnt,
0272 ssize_t total
0273 )
0274 {
0275 test_context *ctx;
0276
0277 ctx = IMFS_generic_get_context_by_iop(iop);
0278 ++ctx->readv_count;
0279
0280 wait();
0281 return 0;
0282 }
0283
0284 static ssize_t handler_writev(
0285 rtems_libio_t *iop,
0286 const struct iovec *iov,
0287 int iovcnt,
0288 ssize_t total
0289 )
0290 {
0291 test_context *ctx;
0292
0293 ctx = IMFS_generic_get_context_by_iop(iop);
0294 ++ctx->writev_count;
0295
0296 wait();
0297 return 0;
0298 }
0299
0300 static const rtems_filesystem_file_handlers_r node_handlers = {
0301 .open_h = handler_open,
0302 .close_h = handler_close,
0303 .read_h = handler_read,
0304 .write_h = handler_write,
0305 .ioctl_h = handler_ioctl,
0306 .lseek_h = handler_lseek,
0307 .fstat_h = handler_fstat,
0308 .ftruncate_h = handler_ftruncate,
0309 .fsync_h = handler_fsync,
0310 .fdatasync_h = handler_fdatasync,
0311 .fcntl_h = handler_fcntl,
0312 .readv_h = handler_readv,
0313 .writev_h = handler_writev
0314 };
0315
0316 static const IMFS_node_control node_control = {
0317 .handlers = &node_handlers,
0318 .node_initialize = IMFS_node_initialize_generic,
0319 .node_remove = IMFS_node_remove_default,
0320 .node_destroy = IMFS_node_destroy_default
0321 };
0322
0323 static void worker_task(rtems_task_argument arg)
0324 {
0325 test_context *ctx;
0326 int rv;
0327 char buf[1];
0328 ssize_t n;
0329 off_t off;
0330 struct iovec iov = {
0331 .iov_base = &buf[0],
0332 .iov_len = sizeof(buf)
0333 };
0334 struct stat st;
0335
0336 ctx = (test_context *) arg;
0337
0338 while (true) {
0339 wait();
0340
0341 switch (ctx->action) {
0342 case ACTION_CLOSE:
0343 ctx->wait_in_close = true;
0344 rv = close(ctx->fd);
0345 rtems_test_assert(rv == 0);
0346 break;
0347 case ACTION_FCNTL:
0348 rv = fcntl(ctx->fd, F_GETFD);
0349 rtems_test_assert(rv >= 0);
0350 break;
0351 case ACTION_FDATASYNC:
0352 rv = fdatasync(ctx->fd);
0353 rtems_test_assert(rv == 0);
0354 break;
0355 case ACTION_FCHDIR:
0356 ctx->wait_in_fstat = true;
0357 rv = fchdir(ctx->fd);
0358 rtems_test_assert(rv == -1);
0359 rtems_test_assert(errno == ENOTDIR);
0360 break;
0361 case ACTION_FCHMOD:
0362 rv = fstat(ctx->fd, &st);
0363 rtems_test_assert(rv == 0);
0364 ctx->wait_in_fstat = true;
0365 rv = fchmod(ctx->fd, st.st_mode);
0366 rtems_test_assert(rv == 0);
0367 break;
0368 case ACTION_FCHOWN:
0369 rv = fstat(ctx->fd, &st);
0370 rtems_test_assert(rv == 0);
0371 ctx->wait_in_fstat = true;
0372 rv = fchown(ctx->fd, st.st_uid, st.st_gid);
0373 rtems_test_assert(rv == 0);
0374 break;
0375 case ACTION_FSTAT:
0376 ctx->wait_in_fstat = true;
0377 rv = fstat(ctx->fd, &st);
0378 rtems_test_assert(rv == 0);
0379 break;
0380 case ACTION_FSYNC:
0381 rv = fsync(ctx->fd);
0382 rtems_test_assert(rv == 0);
0383 break;
0384 case ACTION_FTRUNCATE:
0385 rv = ftruncate(ctx->fd, 0);
0386 rtems_test_assert(rv == 0);
0387 break;
0388 case ACTION_IOCTL:
0389 rv = ioctl(ctx->fd, 0);
0390 rtems_test_assert(rv == 0);
0391 break;
0392 case ACTION_LSEEK:
0393 off = lseek(ctx->fd, 0, SEEK_SET);
0394 rtems_test_assert(off == 0);
0395 break;
0396 case ACTION_READ:
0397 n = read(ctx->fd, buf, sizeof(buf));
0398 rtems_test_assert(n == 0);
0399 break;
0400 case ACTION_READV:
0401 n = readv(ctx->fd, &iov, 1);
0402 rtems_test_assert(n == 0);
0403 break;
0404 case ACTION_WRITE:
0405 n = write(ctx->fd, buf, sizeof(buf));
0406 rtems_test_assert(n == 0);
0407 break;
0408 case ACTION_WRITEV:
0409 n = writev(ctx->fd, &iov, 1);
0410 rtems_test_assert(n == 0);
0411 break;
0412 default:
0413 rtems_test_assert(0);
0414 break;
0415 }
0416 }
0417 }
0418
0419 static void test_fd_free_fifo(const char *path)
0420 {
0421 int a;
0422 int b;
0423 int rv;
0424
0425 a = open(path, O_RDWR);
0426 rtems_test_assert(a >= 0);
0427
0428 rv = close(a);
0429 rtems_test_assert(rv == 0);
0430
0431 b = open(path, O_RDWR);
0432 rtems_test_assert(b >= 0);
0433
0434 rv = close(b);
0435 rtems_test_assert(rv == 0);
0436
0437 rtems_test_assert(a != b);
0438 }
0439
0440 static void test_close(test_context *ctx)
0441 {
0442 const char *path = "generic";
0443 int rv;
0444 rtems_status_code sc;
0445 test_action ac;
0446
0447 rv = IMFS_make_generic_node(
0448 path,
0449 S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
0450 &node_control,
0451 ctx
0452 );
0453 rtems_test_assert(rv == 0);
0454
0455 test_fd_free_fifo(path);
0456
0457 sc = rtems_task_create(
0458 rtems_build_name('W', 'O', 'R', 'K'),
0459 1,
0460 RTEMS_MINIMUM_STACK_SIZE,
0461 RTEMS_DEFAULT_MODES,
0462 RTEMS_DEFAULT_ATTRIBUTES,
0463 &ctx->worker_id
0464 );
0465 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0466
0467 sc = rtems_task_start(
0468 ctx->worker_id,
0469 worker_task,
0470 (rtems_task_argument) ctx
0471 );
0472 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0473
0474 for (ac = ACTION_CLOSE; ac <= ACTION_WRITEV; ++ac) {
0475 rtems_libio_t *iop;
0476 unsigned int flags;
0477 unsigned int expected_flags;
0478
0479 ctx->action = ac;
0480 ctx->fd = open(path, O_RDWR);
0481 rtems_test_assert(ctx->fd >= 0);
0482 iop = rtems_libio_iop(ctx->fd);
0483
0484 wakeup_worker(ctx);
0485 rv = close(ctx->fd);
0486 rtems_test_assert(rv == -1);
0487
0488 if (ac == ACTION_CLOSE) {
0489 rtems_test_assert(errno == EBADF);
0490
0491 flags = rtems_libio_iop_hold(iop);
0492 expected_flags = LIBIO_FLAGS_READ_WRITE;
0493 rtems_test_assert(flags == expected_flags);
0494 flags = rtems_libio_iop_flags(iop);
0495 expected_flags = LIBIO_FLAGS_REFERENCE_INC | LIBIO_FLAGS_READ_WRITE;
0496 rtems_test_assert(flags == expected_flags);
0497 } else {
0498 rtems_test_assert(errno == EBUSY);
0499 }
0500
0501 wakeup_worker(ctx);
0502
0503 if (ac == ACTION_CLOSE) {
0504 flags = rtems_libio_iop_flags(iop);
0505 expected_flags = LIBIO_FLAGS_REFERENCE_INC;
0506 rtems_test_assert(flags == expected_flags);
0507 rtems_libio_iop_drop(iop);
0508 flags = rtems_libio_iop_flags(iop);
0509 expected_flags = 0;
0510 rtems_test_assert(flags == expected_flags);
0511 }
0512
0513 rv = close(ctx->fd);
0514
0515 if (ac == ACTION_CLOSE) {
0516 rtems_test_assert(rv == -1);
0517 rtems_test_assert(errno == EBADF);
0518 } else {
0519 rtems_test_assert(rv == 0);
0520 }
0521 }
0522
0523 sc = rtems_task_delete(ctx->worker_id);
0524 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0525
0526 rv = unlink(path);
0527 rtems_test_assert(rv == 0);
0528
0529 rtems_test_assert(ctx->close_count == 17);
0530 rtems_test_assert(ctx->fcntl_count == 1);
0531 rtems_test_assert(ctx->fdatasync_count == 1);
0532 rtems_test_assert(ctx->fstat_count == 42);
0533 rtems_test_assert(ctx->fsync_count == 1);
0534 rtems_test_assert(ctx->ftruncate_count == 1);
0535 rtems_test_assert(ctx->ioctl_count == 1);
0536 rtems_test_assert(ctx->lseek_count == 1);
0537 rtems_test_assert(ctx->open_count == 17);
0538 rtems_test_assert(ctx->read_count == 1);
0539 rtems_test_assert(ctx->readv_count == 1);
0540 rtems_test_assert(ctx->write_count == 1);
0541 rtems_test_assert(ctx->writev_count == 1);
0542 }
0543
0544 static void test_tmpfile(test_context *ctx)
0545 {
0546 rtems_resource_snapshot before;
0547 FILE *f;
0548 int rv;
0549
0550 rv = mkdir("/tmp", S_IRWXU | S_IRWXG | S_IRWXO);
0551 rtems_test_assert(rv == 0);
0552
0553 f = tmpfile();
0554 rtems_test_assert(f != NULL);
0555 rv = fclose(f);
0556 rtems_test_assert(rv == 0);
0557
0558 rtems_resource_snapshot_take(&before);
0559 f = tmpfile();
0560 rtems_test_assert(f != NULL);
0561 rv = fclose(f);
0562 rtems_test_assert(rv == 0);
0563 rtems_test_assert(rtems_resource_snapshot_check(&before));
0564 }
0565
0566 static void Init(rtems_task_argument arg)
0567 {
0568 TEST_BEGIN();
0569 test_close(&test_instance);
0570 test_tmpfile(&test_instance);
0571 TEST_END();
0572 rtems_test_exit(0);
0573 }
0574
0575 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0576 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0577
0578 #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5
0579
0580 #define CONFIGURE_MAXIMUM_TASKS 2
0581
0582 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0583
0584 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0585
0586 #define CONFIGURE_INIT_TASK_PRIORITY 2
0587 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
0588 #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
0589
0590 #define CONFIGURE_INIT
0591
0592 #include <rtems/confdefs.h>