/* * Based on the example by Max Vilimpoc see: https://vilimpoc.org/research/raii-in-c/ * * The modified code is part of the "Simplified error handling without goto" blog post on * www.softwareprofessional.nl. * * The example has been modified to greatly simplify the error handling, such that the * main flow becomes obvious immediately. * * Jack Goossen */ #include #include #include #include #include #include #include #include #include typedef enum my_error_t { ERROR_NONE = 0, ERROR_RANDOM, ERROR_MEMORY, ERROR_FILE, ERROR_SOCKET, ERROR_SHARED_MEMORY, } my_error_t; /* Generate errors 25% of the time. */ static void randBomb(my_error_t *pError) { if (*pError) return; static int seeded = 0; if (!seeded) { srand(time(NULL)); seeded = 1; } /* Flip a coin. */ if ( (rand() % 5) / 4 ) { *pError = ERROR_RANDOM; fprintf(stderr, "Random exception!\n"); } } static void *my_malloc(size_t size, my_error_t *pError) { if (*pError) return NULL; void *ret = malloc(size); if (NULL == ret) { *pError = ERROR_MEMORY; fprintf(stderr, "malloc() failed.\n"); } return ret; } static FILE *my_fopen(const char *filename, const char *mode, my_error_t *pError) { if (*pError) return NULL; FILE *ret = fopen(filename, mode); if (NULL == ret) { *pError = ERROR_FILE; fprintf(stderr, "fopen() failed.\n"); } return ret; } static int my_socket(int domain, int type, int protocol, my_error_t *pError) { if (*pError) return -1; int ret = socket(domain, type, protocol); if (ret < 0) { *pError = ERROR_SOCKET; fprintf(stderr, "socket() failed.\n"); } return ret; } static int my_shmget(key_t key, size_t size, int shmflg, my_error_t *pError) { if (*pError) return -1; int ret = shmget(key, size, shmflg); if (ret < 0) { *pError = ERROR_SHARED_MEMORY; fprintf(stderr, "shmget() failed!\n"); } return ret; } static void *my_shmat(int shmid, const void *shmaddr, int shmflg, my_error_t *pError) { if (*pError) return NULL; void *ret = shmat(shmid, shmaddr, shmflg); if (NULL == ret) { *pError = ERROR_FILE; fprintf(stderr, "shmat() failed!\n"); } return ret; } static int my_sem_init(sem_t *sem, int pshared, unsigned int value, my_error_t *pError) { if (*pError) return -1; int ret = sem_init(sem, pshared, value); if (ret < 0) { *pError = ERROR_SHARED_MEMORY; fprintf(stderr, "sem_init() failed.\n"); } return ret; } static char *shmRegion; static sem_t st; int main(int argc, char **argv) { my_error_t error = ERROR_NONE; printf("Allocate a memory buffer.\n"); char *memBuf = (char *)my_malloc(256 * 1024, &error); randBomb(&error); FILE *fp = my_fopen("dummy-file.txt", "w", &error); randBomb(&error); printf("Open a socket.\n"); int sock = my_socket(AF_INET, SOCK_DGRAM, 0, &error); randBomb(&error); printf("Create a shared-memory region.\n"); int shmId = my_shmget(0x1234ABCD, 256*1024, IPC_CREAT, &error); char *shmRegion = (char *)my_shmat(shmId, NULL, 0, &error); randBomb(&error); printf("Create/grab a semaphore.\n"); /* semaphore's only available to this process and children. */ int sem_initialized = my_sem_init(&st, 0, 1, &error); randBomb(&error); printf("--> All Resources Allocated!\n"); printf("--> Perform some normal operations, sing a song, take a dump.\n"); if (sem_initialized == 0) { sem_destroy(&st); printf("Semaphore destroyed!\n"); } if (shmId > 0){ shmctl(shmId, IPC_RMID, NULL); printf("Shared memory region destroyed!\n"); } if (sock > 0) { close(sock); printf("Socket closed!\n"); } if (fp > 0) { fclose(fp); printf("File handle closed!\n"); } if (memBuf) { free(memBuf); printf("Memory buffer freed!\n"); } printf("retVal: %d\n", -error); return -error; }