source: rtems/testsuites/psxtests/psxsem01/init.c @ c090db7

5
Last change on this file since c090db7 was c090db7, checked in by Sebastian Huber <sebastian.huber@…>, on 09/12/17 at 06:09:16

posix: Implement self-contained POSIX semaphores

For semaphore object pointer and object validation see
POSIX_SEMAPHORE_VALIDATE_OBJECT().

Destruction or close of a busy semaphore returns an error status. The
object is not flushed.

POSIX semaphores are now available in all configurations and no longer
depend on --enable-posix.

Update #2514.
Update #3116.

  • Property mode set to 100644
File size: 17.1 KB
Line 
1/*
2 *  COPYRIGHT (c) 1989-2012.
3 *  On-Line Applications Research Corporation (OAR).
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.org/license/LICENSE.
8 */
9
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14#include <sched.h>
15#include <semaphore.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <limits.h>
19#include <time.h>
20#include <tmacros.h>
21#include <pmacros.h>
22#include "test_support.h"
23
24const char rtems_test_name[] = "PSXSEM 1";
25
26/* forward declarations to avoid warnings */
27void *POSIX_Init(void *argument);
28
29#define MAX_SEMS  10
30
31static void *sem_wait_task(void *arg)
32{
33  sem_t *sem;
34  int    rv;
35
36  sem = arg;
37
38  rv = sem_wait( sem );
39  rtems_test_assert( rv == 0 );
40
41  rv = sem_wait( sem );
42  rtems_test_assert( rv == 0 );
43
44  return NULL;
45}
46
47static void test_sem_wait_during_delete(void)
48{
49  sem_t     sem;
50  int       rv;
51  pthread_t th;
52  int       eno;
53  int       val;
54
55  rv = sem_init( &sem, 0, 1 );
56  rtems_test_assert( rv == 0 );
57
58  eno = pthread_create( &th, NULL, sem_wait_task, &sem );
59  rtems_test_assert( eno == 0 );
60
61  rv = sem_getvalue( &sem, &val );
62  rtems_test_assert( rv == 0 );
63  rtems_test_assert( val == 1 );
64
65  sched_yield();
66
67  rv = sem_getvalue( &sem, &val );
68  rtems_test_assert( rv == 0 );
69  rtems_test_assert( val == 0 );
70
71  errno = 0;
72  rv = sem_destroy( &sem );
73  rtems_test_assert( rv == -1 );
74  rtems_test_assert( errno == EBUSY );
75
76  rv = sem_post( &sem );
77  rtems_test_assert( rv == 0 );
78
79  eno = pthread_join( th, NULL );
80  rtems_test_assert( eno == 0 );
81
82  rv = sem_destroy( &sem );
83  rtems_test_assert( rv == 0 );
84}
85
86static void test_named_sem_wait_during_delete(void)
87{
88  sem_t     *sem;
89  sem_t     *sem2;
90  int        rv;
91  pthread_t  th;
92  int        eno;
93  int        val;
94
95  sem = sem_open( "sem", O_CREAT | O_EXCL, 0777, 1 );
96  rtems_test_assert( sem != SEM_FAILED );
97
98  sem2 = sem_open( "sem", 0 );
99  rtems_test_assert( sem2 != SEM_FAILED );
100  rtems_test_assert( sem == sem2 );
101
102  eno = pthread_create( &th, NULL, sem_wait_task, sem );
103  rtems_test_assert( eno == 0 );
104
105  rv = sem_getvalue( sem, &val );
106  rtems_test_assert( rv == 0 );
107  rtems_test_assert( val == 1 );
108
109  sched_yield();
110
111  rv = sem_getvalue( sem, &val );
112  rtems_test_assert( rv == 0 );
113  rtems_test_assert( val == 0 );
114
115  rv = sem_close( sem2 );
116  rtems_test_assert( rv == 0 );
117
118  errno = 0;
119  rv = sem_close( sem );
120  rtems_test_assert( rv == -1 );
121  rtems_test_assert( errno == EBUSY );
122
123  rv = sem_post( sem );
124  rtems_test_assert( rv == 0 );
125
126  eno = pthread_join( th, NULL );
127  rtems_test_assert( eno == 0 );
128
129  rv = sem_close( sem );
130  rtems_test_assert( rv == 0 );
131
132  rv = sem_unlink( "sem" );
133  rtems_test_assert( rv == 0 );
134}
135
136static void test_sem_post_overflow(void)
137{
138  sem_t sem;
139  int   rv;
140  int   val;
141
142  rv = sem_init( &sem, 0, SEM_VALUE_MAX );
143  rtems_test_assert( rv == 0 );
144
145  rv = sem_getvalue( &sem, &val );
146  rtems_test_assert( rv == 0 );
147  rtems_test_assert( val == (int) SEM_VALUE_MAX );
148
149  errno = 0;
150  rv = sem_post( &sem );
151  rtems_test_assert( rv == -1 );
152  rtems_test_assert( errno == EOVERFLOW );
153
154  rv = sem_getvalue( &sem, &val );
155  rtems_test_assert( rv == 0 );
156  rtems_test_assert( val == (int) SEM_VALUE_MAX );
157
158  rv = sem_wait( &sem );
159  rtems_test_assert( rv == 0 );
160
161  rv = sem_post( &sem );
162  rtems_test_assert( rv == 0 );
163
164  rv = sem_destroy( &sem );
165  rtems_test_assert( rv == 0 );
166}
167
168static void test_sem_init_too_large_inital_value(void)
169{
170  sem_t  sem;
171  sem_t *sem2;
172  int    rv;
173
174  errno = 0;
175  rv = sem_init( &sem, 0, (unsigned int) SEM_VALUE_MAX + 1 );
176  rtems_test_assert( rv == -1 );
177  rtems_test_assert( errno == EINVAL );
178
179  errno = 0;
180  sem2 = sem_open(
181    "sem",
182    O_CREAT | O_EXCL,
183    0777,
184    (unsigned int) SEM_VALUE_MAX + 1
185  );
186  rtems_test_assert( sem2 == SEM_FAILED );
187  rtems_test_assert( errno == EINVAL );
188}
189
190static void test_sem_null(void)
191{
192  int rv;
193  int val;
194  struct timespec to;
195
196  rtems_test_assert( NULL == SEM_FAILED );
197
198  errno = 0;
199  rv = sem_init( NULL, 0, 0 );
200  rtems_test_assert( rv == -1 );
201  rtems_test_assert( errno == EINVAL );
202
203  errno = 0;
204  rv = sem_wait( NULL );
205  rtems_test_assert( rv == -1 );
206  rtems_test_assert( errno == EINVAL );
207
208  errno = 0;
209  rv = sem_post( NULL );
210  rtems_test_assert( rv == -1 );
211  rtems_test_assert( errno == EINVAL );
212
213  errno = 0;
214  rv = sem_wait( NULL );
215  rtems_test_assert( rv == -1 );
216  rtems_test_assert( errno == EINVAL );
217
218  errno = 0;
219  rv = sem_trywait( NULL );
220  rtems_test_assert( rv == -1 );
221  rtems_test_assert( errno == EINVAL );
222
223  to.tv_sec = 1;
224  to.tv_nsec = 1;
225  errno = 0;
226  rv = sem_timedwait( NULL, &to );
227  rtems_test_assert( rv == -1 );
228  rtems_test_assert( errno == EINVAL );
229
230  errno = 0;
231  rv = sem_getvalue( NULL, &val );
232  rtems_test_assert( rv == -1 );
233  rtems_test_assert( errno == EINVAL );
234
235  errno = 0;
236  rv = sem_destroy( NULL );
237  rtems_test_assert( rv == -1 );
238  rtems_test_assert( errno == EINVAL );
239
240  errno = 0;
241  rv = sem_close( NULL );
242  rtems_test_assert( rv == -1 );
243  rtems_test_assert( errno == EINVAL );
244}
245
246static void test_sem_not_initialized(void)
247{
248  sem_t sem;
249  int rv;
250  int val;
251  struct timespec to;
252
253  memset( &sem, 0xff, sizeof( sem ) );
254
255  errno = 0;
256  rv = sem_wait( &sem );
257  rtems_test_assert( rv == -1 );
258  rtems_test_assert( errno == EINVAL );
259
260  errno = 0;
261  rv = sem_post( &sem );
262  rtems_test_assert( rv == -1 );
263  rtems_test_assert( errno == EINVAL );
264
265  errno = 0;
266  rv = sem_wait( &sem );
267  rtems_test_assert( rv == -1 );
268  rtems_test_assert( errno == EINVAL );
269
270  errno = 0;
271  rv = sem_trywait( &sem );
272  rtems_test_assert( rv == -1 );
273  rtems_test_assert( errno == EINVAL );
274
275  to.tv_sec = 1;
276  to.tv_nsec = 1;
277  errno = 0;
278  rv = sem_timedwait( &sem, &to );
279  rtems_test_assert( rv == -1 );
280  rtems_test_assert( errno == EINVAL );
281
282  errno = 0;
283  rv = sem_getvalue( &sem, &val );
284  rtems_test_assert( rv == -1 );
285  rtems_test_assert( errno == EINVAL );
286
287  errno = 0;
288  rv = sem_destroy( &sem );
289  rtems_test_assert( rv == -1 );
290  rtems_test_assert( errno == EINVAL );
291
292  errno = 0;
293  rv = sem_close( &sem );
294  rtems_test_assert( rv == -1 );
295  rtems_test_assert( errno == EINVAL );
296}
297
298static void test_sem_invalid_copy(void)
299{
300  sem_t sem;
301  sem_t sem2;
302  int   rv;
303  int   val;
304
305  rv = sem_init( &sem, 0, 0 );
306  rtems_test_assert( rv == 0 );
307
308  val = 1;
309  rv = sem_getvalue( &sem, &val );
310  rtems_test_assert( rv == 0 );
311  rtems_test_assert( val == 0 );
312
313  memcpy( &sem2, &sem, sizeof( sem2 ) );
314
315  errno = 0;
316  rv = sem_getvalue( &sem2, &val );
317  rtems_test_assert( rv == -1 );
318  rtems_test_assert( errno == EINVAL );
319
320  rv = sem_destroy( &sem );
321  rtems_test_assert( rv == 0 );
322
323  errno = 0;
324  rv = sem_getvalue( &sem, &val );
325  rtems_test_assert( rv == -1 );
326  rtems_test_assert( errno == EINVAL );
327}
328
329void *POSIX_Init(
330  void *argument
331)
332{
333  int             status;
334  int             value;
335  int             i;
336  sem_t           sems[MAX_SEMS];
337  sem_t           sem2;
338  sem_t           *n_sem1;
339  sem_t           *n_sem2;
340  struct timespec waittime;
341  char            failure_msg[80];
342
343  TEST_BEGIN();
344
345  puts( "Init: sem_init - SUCCESSFUL" );
346  status = sem_init(&sem2, 1, 1);
347  fatal_posix_service_status( status, 0, "sem_init with pshared != 0");
348
349  puts( "Init: sem_destroy - SUCCESSFUL" );
350  status = sem_destroy(&sem2);
351  fatal_posix_service_status( status, 0, "sem_destroy");
352
353  puts( "Init: sem_init - UNSUCCESSFUL (EINVAL)" );
354  status = sem_init(NULL, 0, 1);
355  fatal_posix_service_status( status, -1, "sem_init error return status");
356  fatal_posix_service_status( errno, EINVAL, "sem_init errorno EINVAL" );
357
358  puts( "Init: sem_init - SUCCESSFUL" );
359  for (i = 0; i < MAX_SEMS; i++) {
360    status = sem_init(&sems[i], 0, i);
361    sprintf(failure_msg, "sem_init %d", i );
362    fatal_posix_service_status( status, 0, failure_msg);
363  }
364
365  puts( "Init: sem_init - SUCCESSFUL" );
366  status = sem_init(&sem2, 0, 1);
367  fatal_posix_service_status( status, 0, "sem_init");
368
369  puts( "Init: sem_destroy - SUCCESSFUL" );
370  status = sem_destroy(&sem2);
371  fatal_posix_service_status( status, 0, "sem_destroy");
372
373  puts( "Init: sem_getvalue - SUCCESSFUL ");
374  for (i = 0; i < MAX_SEMS; i++) {
375    status = sem_getvalue(&sems[i], &value);
376    sprintf( failure_msg, "sem_getvalue %d", i );
377    fatal_posix_service_status( status, 0, failure_msg );
378    fatal_posix_service_status( value, i, "sem_getvalue correct value" );
379  }
380  puts( "Init: sem_getvalue - UNSUCCESSFUL ");
381  status = sem_getvalue(SEM_FAILED, &value);
382  fatal_posix_service_status( status, -1, "sem_getvalue error return status");
383  fatal_posix_service_status( errno, EINVAL, "sem_getvalue errno EINVAL");
384
385  puts( "Init: sem_destroy - SUCCESSFUL" );
386  status = sem_destroy(&sems[0]);
387  fatal_posix_service_status( status, 0, "sem_destroy semaphore 0");
388
389  puts( "Init: sem_destroy - UNSUCCESSFUL (EINVAL)" );
390  status = sem_destroy(SEM_FAILED);
391  fatal_posix_service_status( status, -1, "sem_destroy error return status");
392  fatal_posix_service_status( errno, EINVAL, "sem_destroy errno EINVAL");
393
394  puts( "Init: sem_wait - SUCCESSFUL" );
395  status = sem_wait(&sems[1]);
396  fatal_posix_service_status( status, 0, "sem_wait semaphore 1");
397  /* sem[1].count = 0 */
398
399  puts( "Init: sem_wait - UNSUCCESSFUL (EINVAL)" );
400  status = sem_wait(SEM_FAILED);
401  fatal_posix_service_status( status, -1, "sem_wait error return status");
402  fatal_posix_service_status( errno, EINVAL, "sem_wait errno EINVAL");
403
404  puts( "Init: sem_post - SUCCESSFUL" );
405  status = sem_post(&sems[1]);
406  fatal_posix_service_status( status, 0, "sem_post semaphore 1");
407  /* sem[1].count = 1 */
408
409  puts( "Init: sem_wait - SUCCESSFUL (after a sem_post)" );
410  status = sem_wait(&sems[1]);
411  fatal_posix_service_status( status, 0, "sem_wait semaphore 1");
412  /* sem[1].count = 0 */
413
414  puts( "Init: sem_trywait - SUCCESSFUL" );
415  status = sem_trywait(&sems[2]);
416  fatal_posix_service_status( status, 0, "sem_trywait semaphore 2");
417  /* sem[2].count = 1 */
418
419  puts( "Init: sem_trywait - UNSUCCESSFUL (EAGAIN)" );
420  status = sem_trywait(&sems[1]);
421  fatal_posix_service_status( status, -1, "sem_trywait error return status");
422  fatal_posix_service_status( errno, EAGAIN, "sem_trywait errno EAGAIN");
423  /* sem[1].count = 0 */
424
425  puts( "Init: sem_trywait - UNSUCCESSFUL (EINVAL)" );
426  status = sem_trywait(SEM_FAILED);
427  fatal_posix_service_status( status, -1, "sem_trywait error return status");
428  fatal_posix_service_status( errno, EINVAL, "sem_trywait errno EINVAL");
429
430#if 0
431  status = sem_post(&sems[2]);
432  fatal_posix_service_status( status, 0, "sem_post semaphore 2");
433  /* sem[2].count = 2 */
434#else
435  /* sem[2].count = 1 */
436#endif
437
438  puts( "Init: sem_timedwait - SUCCESSFUL" );
439  waittime.tv_sec = time(NULL) + 1;
440  waittime.tv_nsec = 100;
441  status = sem_timedwait(&sems[2], &waittime);
442  fatal_posix_service_status( status, 0, "sem_timedwait semaphore 2");
443  /* sem[2].count = 0 */
444
445  puts( "Init: sem_timedwait - UNSUCCESSFUL (ETIMEDOUT)" );
446  status = sem_timedwait(&sems[2], &waittime);
447  fatal_posix_service_status( status, -1, "sem_timedwait error return status");
448  fatal_posix_service_status(
449    errno, ETIMEDOUT, "sem_timedwait errno ETIMEDOUT");
450
451  /*
452   * To do this case, we must be blocking when we want the semaphore.
453   * POSIX doesn't want you to check the error if you can get the resource.
454   */
455
456#if 1
457  puts( "Init: sem_timedwait - UNSUCCESSFUL (EINVAL) -- skipping" );
458#else
459  puts( "Init: sem_timedwait - UNSUCCESSFUL (EINVAL)" );
460  waittime.tv_sec = 0;
461  waittime.tv_nsec = 0x7FFFFFFF;
462  status = sem_timedwait(&sems[2], &waittime);
463  fatal_posix_service_status( status, -1, "sem_timedwait error return status");
464  fatal_posix_service_status( errno, EINVAL, "sem_init errno EINVAL");
465#endif
466
467  puts( "Init: sem_post - UNSUCCESSFUL (EINVAL)" );
468  status = sem_post(SEM_FAILED);
469  fatal_posix_service_status( status, -1, "sem_post error return status");
470  fatal_posix_service_status( errno, EINVAL, "sem_post errno EINVAL");
471
472  puts( "Init: sem_destroy - SUCCESSFUL" );
473  for (i = 1; i < MAX_SEMS; i++) {
474    status = sem_destroy(&sems[i]);
475    sprintf( failure_msg, "sem_destroy %d", i );
476    fatal_posix_service_status( status, 0, failure_msg );
477  }
478
479  /* Modes are currently unsupported */
480
481  /*
482   * Validate all sem_open return paths.
483   */
484
485  puts( "Init: sem_open - UNSUCCESSFUL (ENAMETOOLONG)" );
486  n_sem1 = sem_open(Get_Too_Long_Name(), O_CREAT, 0777, 1 );
487  fatal_posix_sem( n_sem1, "sem_open error return status" );
488  fatal_posix_service_status(
489    errno, ENAMETOOLONG, "sem_open errorno ENAMETOOLONG" );
490
491  puts( "Init: sem_open - sem1 SUCCESSFUL" );
492  n_sem1 = sem_open( "sem1",O_CREAT, 0777, 1 );
493  rtems_test_assert( n_sem1 != SEM_FAILED );
494
495  puts( "Init: sem_destroy - named sem1 - EINVAL" );
496  status = sem_destroy(n_sem1);
497  fatal_posix_service_status( status, -1, "sem_destroy named semaphore");
498  fatal_posix_service_status( errno, EINVAL,  "sem_destroy named semaphore");
499
500  puts( "Init: sem_open - Create an Existing sem (EEXIST)" );
501  n_sem2 = sem_open("sem1", O_CREAT | O_EXCL, 0777, 1);
502  fatal_posix_sem( n_sem2, "sem_open error return status" );
503  fatal_posix_service_status( errno, EEXIST,  "sem_open errno EEXIST");
504
505  puts( "Init: sem_open - Open new sem without create flag (ENOENT)" );
506  n_sem2 = sem_open("sem3", O_EXCL, 0777, 1);
507  fatal_posix_sem( n_sem2, "sem_open error return status" );
508  fatal_posix_service_status( errno, ENOENT,  "sem_open errno EEXIST");
509
510  /*
511   * XXX - Could not hit the following errors:
512   *   E_POSIX_Semaphore_Create_support only fails if
513   *     ENOSYS - When semaphore is shared between processes.
514   *     ENOSPC - When out of memory.
515   */
516
517  /*
518   * Validate we can wait on a semaphore opened with sem_open.
519   */
520
521  puts( "Init: sem_wait on sem1" );
522  status = sem_wait(n_sem1);
523  fatal_posix_service_status( status, 0, "sem_wait opened semaphore");
524
525  /*
526   * Validate a second open returns the same semaphore.
527   */
528
529  puts( "Init: sem_open - Open an existing sem ( same id )" );
530  n_sem2 = sem_open("sem1", 0 );
531  rtems_test_assert( n_sem2 == n_sem1 );
532
533  /*
534   * Unlink the semaphore, then verify an open of the same name produces a
535   * different semaphore.
536   */
537
538  puts( "Init: sem_unlink - sem1 SUCCESSFUL" );
539  status = sem_unlink( "sem1" );
540  fatal_posix_service_status( status, 0, "sem_unlink locked semaphore");
541
542  puts( "Init: sem_open - Reopen sem1 SUCCESSFUL with a different id" );
543  n_sem2 = sem_open( "sem1", O_CREAT | O_EXCL, 0777, 1);
544  rtems_test_assert( n_sem2 != SEM_FAILED );
545  rtems_test_assert( n_sem2 != n_sem1 );
546
547  /*
548   * Validate we can call close on a semaphore opened with sem_open.
549   */
550
551  puts( "Init: sem_close (1) - SUCCESSFUL" );
552  status = sem_close( n_sem1 );
553  fatal_posix_service_status( status, 0, "sem_close semaphore");
554
555  /*
556   * Validate it n_sem2 (the last open for sem1 name can be
557   * correctly closed and unlinked.
558   */
559
560  puts( "Init: sem_close (2) - SUCCESSFUL" );
561  status = sem_close( n_sem2 );
562  fatal_posix_service_status( status, 0, "sem_close semaphore");
563
564  puts( "Init: sem_unlink - sem1 (2) SUCCESSFUL" );
565  status = sem_unlink( "sem1" );
566  fatal_posix_service_status( status, 0, "sem_unlink locked semaphore");
567
568  puts( "Init: sem_close - UNSUCCESSFUL (EINVAL)" );
569  status = sem_close(n_sem2);
570  fatal_posix_service_status( status, -1, "sem_close error return status");
571  fatal_posix_service_status( errno, EINVAL, "sem_close errno EINVAL");
572
573  puts( "Init: sem_unlink - UNSUCCESSFUL (ENOENT)" );
574  status = sem_unlink("sem1");
575  fatal_posix_service_status( status, -1, "sem_unlink error return status");
576  fatal_posix_service_status( errno, ENOENT, "sem_close errno EINVAL");
577
578
579  /*
580   * Validate we can unlink (2)
581   */
582
583  puts( "Init: sem_unlink (NULL) - EINVAL" );
584  status = sem_unlink( NULL );
585  fatal_posix_service_status( status, -1, "sem_unlink error return status");
586  fatal_posix_service_status( errno, EINVAL, "sem_unlink errno value");
587
588  puts( "Init: sem_unlink (\"\") - ENOENT" );
589  status = sem_unlink( "" );
590  fatal_posix_service_status( status, -1, "sem_unlink error return status");
591  fatal_posix_service_status( errno, ENOENT, "sem_unlink errno value");
592
593  /*
594   * XXX - Cant' create location OBJECTS_ERROR or OBJECTS_REMOTE.
595   *       sem_close and sem_unlink.
596   */
597
598  puts( "Init: sem_unlink - UNSUCCESSFUL (ENOENT)" );
599  status = sem_unlink("sem2");
600  fatal_posix_service_status( status, -1, "sem_unlink error return status");
601  fatal_posix_service_status( errno, ENOENT, "sem_unlink errno ENOENT");
602  rtems_test_assert( (status == -1) && (errno == ENOENT) );
603
604  test_named_sem_wait_during_delete();
605  test_sem_wait_during_delete();
606  test_sem_post_overflow();
607  test_sem_init_too_large_inital_value();
608  test_sem_null();
609  test_sem_not_initialized();
610  test_sem_invalid_copy();
611
612  /* Try adding in unlinking before closing... (can we still open?) */
613
614  TEST_END();
615  rtems_test_exit(0);
616
617  return NULL; /* just so the compiler thinks we returned something */
618}
619
620/* configuration information */
621#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
622#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
623
624#define CONFIGURE_POSIX_INIT_THREAD_TABLE
625
626#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
627
628#define CONFIGURE_MAXIMUM_POSIX_THREADS     2
629#define CONFIGURE_MAXIMUM_POSIX_SEMAPHORES  2
630
631#define CONFIGURE_POSIX_INIT_THREAD_TABLE
632#define CONFIGURE_POSIX_INIT_THREAD_STACK_SIZE \
633        (RTEMS_MINIMUM_STACK_SIZE * 4)
634
635#define CONFIGURE_INIT
636#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.