summaryrefslogtreecommitdiff
path: root/gl/msvc-inval.c
blob: b7a917d59a5bd055fb89442f22d1826fea1c167e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* Invalid parameter handler for MSVC runtime libraries.
   Copyright (C) 2011-2012 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#include <config.h>

/* Specification.  */
#include "msvc-inval.h"

#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)

/* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
   declaration.  */
# include <stdlib.h>

# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING

static void cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
                                   const wchar_t *function,
                                   const wchar_t *file,
                                   unsigned int line,
                                   uintptr_t dummy)
{
}

# else

/* Get declarations of the native Windows API functions.  */
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>

#  if defined _MSC_VER

static void cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
                                   const wchar_t *function,
                                   const wchar_t *file,
                                   unsigned int line,
                                   uintptr_t dummy)
{
  RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
}

#  else

/* An index to thread-local storage.  */
static DWORD tls_index;
static int tls_initialized /* = 0 */;

/* Used as a fallback only.  */
static struct gl_msvc_inval_per_thread not_per_thread;

struct gl_msvc_inval_per_thread *
gl_msvc_inval_current (void)
{
  if (!tls_initialized)
    {
      tls_index = TlsAlloc ();
      tls_initialized = 1;
    }
  if (tls_index == TLS_OUT_OF_INDEXES)
    /* TlsAlloc had failed.  */
    return &not_per_thread;
  else
    {
      struct gl_msvc_inval_per_thread *pointer =
        (struct gl_msvc_inval_per_thread *) TlsGetValue (tls_index);
      if (pointer == NULL)
        {
          /* First call.  Allocate a new 'struct gl_msvc_inval_per_thread'.  */
          pointer =
            (struct gl_msvc_inval_per_thread *)
            malloc (sizeof (struct gl_msvc_inval_per_thread));
          if (pointer == NULL)
            /* Could not allocate memory.  Use the global storage.  */
            pointer = &not_per_thread;
          TlsSetValue (tls_index, pointer);
        }
      return pointer;
    }
}

static void cdecl
gl_msvc_invalid_parameter_handler (const wchar_t *expression,
                                   const wchar_t *function,
                                   const wchar_t *file,
                                   unsigned int line,
                                   uintptr_t dummy)
{
  struct gl_msvc_inval_per_thread *current = gl_msvc_inval_current ();
  if (current->restart_valid)
    longjmp (current->restart, 1);
  else
    /* An invalid parameter notification from outside the gnulib code.
       Give the caller a chance to intervene.  */
    RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
}

#  endif

# endif

static int gl_msvc_inval_initialized /* = 0 */;

void
gl_msvc_inval_ensure_handler (void)
{
  if (gl_msvc_inval_initialized == 0)
    {
      _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
      gl_msvc_inval_initialized = 1;
    }
}

#endif