1 /*
2  * This file is part of MPSolve 3.2.1
3  *
4  * Copyright (C) 2001-2020, Dipartimento di Matematica "L. Tonelli", Pisa.
5  * License: http://www.gnu.org/licenses/gpl.html GPL version 3 or higher
6  *
7  * Authors:
8  *   Dario Andrea Bini <bini@dm.unipi.it>
9  *   Giuseppe Fiorentino <fiorent@dm.unipi.it>
10  *   Leonardo Robol <leonardo.robol@unipi.it>
11  */
12 
13 
14 #include <mps/mps.h>
15 #include <mps/link.h>
16 #include <gmp.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <assert.h>
21 
22 #ifdef MPS_CATCH_FPE
23 #include <fenv.h>
24 int feenableexcept (int excepts);
25 #endif
26 
27 #if HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30 #undef malloc
31 #undef realloc
32 
33 void *malloc (size_t n);
34 void *realloc (void * ptr, size_t n);
35 
36 /**
37  * @brief Perform some preliminary checks and setup before starting the real
38  * MPSolve loop.
39  */
40 static void
mps_preliminary_setup(mps_context * ctx)41 mps_preliminary_setup (mps_context * ctx)
42 {
43   /* Make sure that non thread safe polynomial implementations are handled
44    * in a safe way. */
45   if (!ctx->active_poly->thread_safe)
46     {
47       mps_thread_pool_set_concurrency_limit (ctx, NULL, 1);
48     }
49 }
50 
51 /**
52  * @brief Call the real polynomial (or secular equation, or whatever) solver
53  * and do the computation.
54  *
55  * The algorithm used must be selected before this call with <code>mps_select_algorithm</code>
56  * and the data (the coefficients, or whatever the algorithm may require) should be provided
57  * after that.
58  *
59  * Roots can then be obtained with the functions <code>mps_context_get_roots_*</code>
60  *
61  */
62 void
mps_mpsolve(mps_context * s)63 mps_mpsolve (mps_context * s)
64 {
65 #ifdef MPS_CATCH_FPE
66   feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
67 #endif
68 
69   if (mps_context_has_errors (s))
70     return;
71 
72   mps_preliminary_setup (s);
73 
74   (*s->mpsolve_ptr)(s);
75 }
76 
77 static void*
mps_caller(mps_context * s)78 mps_caller (mps_context * s)
79 {
80   if (!mps_context_has_errors (s))
81     {
82       mps_preliminary_setup (s);
83       s->mpsolve_ptr (s);
84     }
85 
86   /* Call user defined callback if available */
87   if (s->callback == NULL)
88     return NULL;
89   else
90     return (*s->callback)(s, s->user_data);
91 }
92 
93 void
mps_mpsolve_async(mps_context * s,mps_callback callback,void * user_data)94 mps_mpsolve_async (mps_context * s, mps_callback callback, void * user_data)
95 {
96 #ifdef MPS_CATCH_FPE
97   feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
98 #endif
99 
100   /* Set up callbacks */
101   s->callback = callback;
102   s->user_data = user_data;
103 
104   mps_thread_pool * private_pool = mps_thread_pool_new (s, 1);
105   mps_thread_pool_set_strict_async (private_pool, true);
106   s->self_thread_pool = private_pool;
107   mps_thread_pool_assign (s, private_pool, (mps_thread_work) mps_caller, s);
108 }
109 
110 /**
111  * @brief Allocator for memory to be used in mpsolve.
112  */
113 void *
mps_malloc(size_t size)114 mps_malloc (size_t size)
115 {
116   /* fprintf (stderr, "Allocating %lu bytes of memory\n", size); */
117   register void *value = malloc (size);
118 
119   if (value == 0)
120     {
121       fprintf (stderr, "virtual memory exhausted");
122       abort ();
123     }
124   return value;
125 }
126 
127 /**
128  * @brief Reallocator for memory used in MPSolve.
129  */
130 void *
mps_realloc(void * pointer,size_t size)131 mps_realloc (void * pointer, size_t size)
132 {
133   register void *value = realloc (pointer, size);
134 
135   if (value == 0 && size > 0)
136     {
137       fprintf (stderr, "virtual memory exhausted");
138       abort ();
139     }
140   return value;
141 }
142