...

Text file src/cmd/cgo/internal/testcarchive/testdata/main4.c

Documentation: cmd/cgo/internal/testcarchive/testdata

     1// Copyright 2015 The Go Authors. All rights reserved.
     2// Use of this source code is governed by a BSD-style
     3// license that can be found in the LICENSE file.
     4
     5// Test a C thread that calls sigaltstack and then calls Go code.
     6
     7#include <signal.h>
     8#include <stdio.h>
     9#include <stdlib.h>
    10#include <string.h>
    11#include <time.h>
    12#include <sched.h>
    13#include <pthread.h>
    14
    15#include "libgo4.h"
    16
    17#ifdef _AIX
    18// On AIX, CSIGSTKSZ is too small to handle Go sighandler.
    19#define CSIGSTKSZ 0x4000
    20#else
    21#define CSIGSTKSZ SIGSTKSZ
    22#endif
    23
    24static void die(const char* msg) {
    25	perror(msg);
    26	exit(EXIT_FAILURE);
    27}
    28
    29static int ok = 1;
    30
    31static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
    32}
    33
    34// Set up the SIGIO signal handler in a high priority constructor, so
    35// that it is installed before the Go code starts.
    36
    37static void init(void) __attribute__ ((constructor (200)));
    38
    39static void init() {
    40	struct sigaction sa;
    41
    42	memset(&sa, 0, sizeof sa);
    43	sa.sa_sigaction = ioHandler;
    44	if (sigemptyset(&sa.sa_mask) < 0) {
    45		die("sigemptyset");
    46	}
    47	sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
    48	if (sigaction(SIGIO, &sa, NULL) < 0) {
    49		die("sigaction");
    50	}
    51}
    52
    53// Test raising SIGIO on a C thread with an alternate signal stack
    54// when there is a Go signal handler for SIGIO.
    55static void* thread1(void* arg __attribute__ ((unused))) {
    56	stack_t ss;
    57	int i;
    58	stack_t nss;
    59	struct timespec ts;
    60
    61	// Set up an alternate signal stack for this thread.
    62	memset(&ss, 0, sizeof ss);
    63	ss.ss_sp = malloc(CSIGSTKSZ);
    64	if (ss.ss_sp == NULL) {
    65		die("malloc");
    66	}
    67	ss.ss_flags = 0;
    68	ss.ss_size = CSIGSTKSZ;
    69	if (sigaltstack(&ss, NULL) < 0) {
    70		die("sigaltstack");
    71	}
    72
    73	// Send ourselves a SIGIO.  This will be caught by the Go
    74	// signal handler which should forward to the C signal
    75	// handler.
    76	i = pthread_kill(pthread_self(), SIGIO);
    77	if (i != 0) {
    78		fprintf(stderr, "pthread_kill: %s\n", strerror(i));
    79		exit(EXIT_FAILURE);
    80	}
    81
    82	// Wait until the signal has been delivered.
    83	i = 0;
    84	while (SIGIOCount() == 0) {
    85		ts.tv_sec = 0;
    86		ts.tv_nsec = 1000000;
    87		nanosleep(&ts, NULL);
    88		i++;
    89		if (i > 5000) {
    90			fprintf(stderr, "looping too long waiting for signal\n");
    91			exit(EXIT_FAILURE);
    92		}
    93	}
    94
    95	// We should still be on the same signal stack.
    96	if (sigaltstack(NULL, &nss) < 0) {
    97		die("sigaltstack check");
    98	}
    99	if ((nss.ss_flags & SS_DISABLE) != 0) {
   100		fprintf(stderr, "sigaltstack disabled on return from Go\n");
   101		ok = 0;
   102	} else if (nss.ss_sp != ss.ss_sp) {
   103		fprintf(stderr, "sigaltstack changed on return from Go\n");
   104		ok = 0;
   105	}
   106
   107	return NULL;
   108}
   109
   110// Test calling a Go function to raise SIGIO on a C thread with an
   111// alternate signal stack when there is a Go signal handler for SIGIO.
   112static void* thread2(void* arg __attribute__ ((unused))) {
   113	stack_t ss;
   114	int i;
   115	int oldcount;
   116	pthread_t tid;
   117	struct timespec ts;
   118	stack_t nss;
   119
   120	// Set up an alternate signal stack for this thread.
   121	memset(&ss, 0, sizeof ss);
   122	ss.ss_sp = malloc(CSIGSTKSZ);
   123	if (ss.ss_sp == NULL) {
   124		die("malloc");
   125	}
   126	ss.ss_flags = 0;
   127	ss.ss_size = CSIGSTKSZ;
   128	if (sigaltstack(&ss, NULL) < 0) {
   129		die("sigaltstack");
   130	}
   131
   132	oldcount = SIGIOCount();
   133
   134	// Call a Go function that will call a C function to send us a
   135	// SIGIO.
   136	tid = pthread_self();
   137	GoRaiseSIGIO(&tid);
   138
   139	// Wait until the signal has been delivered.
   140	i = 0;
   141	while (SIGIOCount() == oldcount) {
   142		ts.tv_sec = 0;
   143		ts.tv_nsec = 1000000;
   144		nanosleep(&ts, NULL);
   145		i++;
   146		if (i > 5000) {
   147			fprintf(stderr, "looping too long waiting for signal\n");
   148			exit(EXIT_FAILURE);
   149		}
   150	}
   151
   152	// We should still be on the same signal stack.
   153	if (sigaltstack(NULL, &nss) < 0) {
   154		die("sigaltstack check");
   155	}
   156	if ((nss.ss_flags & SS_DISABLE) != 0) {
   157		fprintf(stderr, "sigaltstack disabled on return from Go\n");
   158		ok = 0;
   159	} else if (nss.ss_sp != ss.ss_sp) {
   160		fprintf(stderr, "sigaltstack changed on return from Go\n");
   161		ok = 0;
   162	}
   163
   164	return NULL;
   165}
   166
   167int main(int argc, char **argv) {
   168	pthread_t tid;
   169	int i;
   170
   171	// Tell the Go library to start looking for SIGIO.
   172	GoCatchSIGIO();
   173
   174	i = pthread_create(&tid, NULL, thread1, NULL);
   175	if (i != 0) {
   176		fprintf(stderr, "pthread_create: %s\n", strerror(i));
   177		exit(EXIT_FAILURE);
   178	}
   179
   180	i = pthread_join(tid, NULL);
   181	if (i != 0) {
   182		fprintf(stderr, "pthread_join: %s\n", strerror(i));
   183		exit(EXIT_FAILURE);
   184	}
   185
   186	i = pthread_create(&tid, NULL, thread2, NULL);
   187	if (i != 0) {
   188		fprintf(stderr, "pthread_create: %s\n", strerror(i));
   189		exit(EXIT_FAILURE);
   190	}
   191
   192	i = pthread_join(tid, NULL);
   193	if (i != 0) {
   194		fprintf(stderr, "pthread_join: %s\n", strerror(i));
   195		exit(EXIT_FAILURE);
   196	}
   197
   198	if (!ok) {
   199		exit(EXIT_FAILURE);
   200	}
   201
   202	printf("PASS\n");
   203	return 0;
   204}

View as plain text