This file is indexed.

/usr/include/trilinos/Teuchos_DefaultComm.hpp is in libtrilinos-teuchos-dev 12.12.1-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
// @HEADER
// ***********************************************************************
//
//                    Teuchos: Common Tools Package
//                 Copyright (2004) Sandia Corporation
//
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
//
// ***********************************************************************
// @HEADER

#ifndef TEUCHOS_DEFAULT_COMM_HPP
#define TEUCHOS_DEFAULT_COMM_HPP

#include "Teuchos_RCP.hpp"
#include "Teuchos_DefaultSerialComm.hpp"
#ifdef HAVE_MPI
#  include "Teuchos_DefaultMpiComm.hpp"
#endif

namespace Teuchos {

#ifdef HAVE_MPI
namespace Details {

template<class OrdinalType>
int
mpiFreeDefaultComm (MPI_Comm, int, void*, void*);

template<class OrdinalType>
int
mpiFreeDefaultSerialComm (MPI_Comm, int, void*, void*);

} // namespace Details
#endif // HAVE_MPI

/// \class DefaultComm
/// \brief Return a default global communicator appropriate for the build.
///
/// Use this class to get a Comm instance representing the default
/// global communicator.  If Teuchos was built with MPI (i.e., if the
/// HAVE_MPI macro is defined), then the default communicator wraps
/// MPI_COMM_WORLD.  Otherwise, it is a "serial" communicator
/// (containing one process, whose rank is zero).
///
/// \tparam OrdinalType The ordinal type for the Comm communicator
///   wrapper template class.  Comm uses \c OrdinalType to represent
///   things like array lengths and indices.
///
/// \note (mfh 19 Jul 2011, 22 Dec 2011) \c OrdinalType is called
///   <tt>OrdinalType</tt> and not \c Ordinal, because of a bug in
///   Intel's C++ compiler (version 11.1).  This compiler confuses the
///   \c Ordinal template parameter of DefaultComm with the
///   Teuchos::Ordinal typedef.  The \c Ordinal template parameter
///   should actually shadow the typedef in Teuchos, and it does with
///   GCC 4.5.1, but does not with Intel's compiler.  This may be the
///   case with other compilers as well, but I haven't tested them
///   yet.  If this class' template parameter were named \c Ordinal,
///   then the following line of code would result in a compile error:
///   \code
///   RCP<const Comm<int> pComm = DefaultComm<int>::getDefaultSerialComm (null);
///   \endcode
template<typename OrdinalType>
class DefaultComm {
public:
  /// \brief Return the default global communicator.
  ///
  /// \warning When running with MPI, do not call this function until
  ///   after MPI_Init has been called.  You can use GlobalMPISesssion
  ///   to initialize MPI without explicitly depending on the MPI
  ///   interface or the mpi.h header file.  (If Trilinos was not
  ///   built with MPI, GlobalMPISession will do the right thing, so
  ///   you can use it unconditionally.)
  ///
  /// \warning Do not use or refer to the returned object after
  ///   MPI_Finalize has been called.  In a non-MPI build, do not use
  ///   or refer to the returned object after main() has returned.
  static Teuchos::RCP<const Comm<OrdinalType> > getComm ();

  /// \brief Return a serial Comm if the input Comm is null.
  ///
  /// If the input communicator \c comm is null, return the default
  /// serial communicator.  Otherwise, just return the input.
  ///
  /// \warning The same warnings as for getComm() apply here.
  static Teuchos::RCP<const Comm<OrdinalType> >
  getDefaultSerialComm (const Teuchos::RCP<const Comm<OrdinalType> >& comm);

private:
  /// \brief The default global communicator.
  ///
  /// If Teuchos was built with MPI, this is a wrapper for
  /// MPI_COMM_WORLD.  Otherwise, this is a "serial" communicator
  /// (containing one process, whose rank is zero).
  static const Comm<OrdinalType>* comm_;

  //! A "serial" communicator (containing one process, whose rank is zero).
  static const Comm<OrdinalType>* defaultSerialComm_;

#ifdef HAVE_MPI
  //! MPI_Finalize hook that calls freeDefaultComm().
  template<class OT>
  friend int
  Details::mpiFreeDefaultComm (MPI_Comm, int, void*, void*);

  //! MPI_Finalize hook that calls freeDefaultSerialComm().
  template<class OT>
  friend int
  Details::mpiFreeDefaultSerialComm (MPI_Comm, int, void*, void*);
#endif // HAVE_MPI

  //! Free the default Comm object.
  static void freeDefaultComm () {
    if (comm_ != NULL) {
      delete comm_;
      comm_ = NULL;
    }
  }

  //! Free the default serial Comm object.
  static void freeDefaultSerialComm () {
    if (defaultSerialComm_ != NULL) {
      delete defaultSerialComm_;
      defaultSerialComm_ = NULL;
    }
  }
};

#ifdef HAVE_MPI
namespace Details {

template<class OrdinalType>
int
mpiFreeDefaultComm (MPI_Comm, int, void*, void*)
{
  try {
    ::Teuchos::DefaultComm<OrdinalType>::freeDefaultComm ();
  } catch (...) {
    // Destructors must not throw exceptions, so we must accept the
    // possible memory leak and move on.
    std::cerr << "Teuchos::DefaultComm: Failed to free default Comm!  We can't "
      "throw an exception here because this is a singleton destructor that "
      "should only be called at MPI_Finalize or (if not building with MPI) at "
      "exit from main()." << std::endl;
    // FIXME (mfh 16 Nov 2014) There might be some way to create a
    // custom return code with MPI error reporting.  For now, we just
    // pick some error code not equal to MPI_SUCCESS.  It could
    // perhaps overlap with some existing error code.
    return (MPI_SUCCESS == 0) ? -1 : 0;
  }
  return MPI_SUCCESS;
}

template<class OrdinalType>
int
mpiFreeDefaultSerialComm (MPI_Comm, int, void*, void*)
{
  try {
    ::Teuchos::DefaultComm<OrdinalType>::freeDefaultSerialComm ();
  } catch (...) {
    // Destructors must not throw exceptions, so we must accept the
    // possible memory leak and move on.
    std::cerr << "Teuchos::DefaultComm: Failed to free default serial Comm!  "
      "We can't throw an exception here because this is a singleton destructor "
      "that should only be called at MPI_Finalize or (if not building with MPI)"
      " at exit from main()." << std::endl;
    // FIXME (mfh 16 Nov 2014) There might be some way to create a
    // custom return code with MPI error reporting.  For now, we just
    // pick some error code not equal to MPI_SUCCESS.  It could
    // perhaps overlap with some existing error code.
    return (MPI_SUCCESS == 0) ? -1 : 0;
  }
  return MPI_SUCCESS;
}

} // namespace Details
#endif // HAVE_MPI


template<typename OrdinalType>
Teuchos::RCP<const Teuchos::Comm<OrdinalType> >
DefaultComm<OrdinalType>::getComm ()
{
  if (comm_ == NULL) {
#ifdef HAVE_MPI
#  if MPI_VERSION >= 2

    comm_ = new MpiComm<OrdinalType> (MPI_COMM_WORLD);

    // We want comm_ to be deallocated when MPI_Finalize is called.
    // The standard idiom for this (look in the MPI standard) is to
    // register an attribute ((key,value) pair) with MPI_COMM_SELF,
    // with a custom "destructor" to be called at MPI_Finalize.

    // 'key' is an output argument of MPI_Comm_create_keyval.
    int key = MPI_KEYVAL_INVALID;
    int err =
      MPI_Comm_create_keyval (MPI_COMM_NULL_COPY_FN,
                              Details::mpiFreeDefaultComm<OrdinalType>,
                              &key,
                              NULL); // no extra state
    if (err != MPI_SUCCESS) {
      if (comm_ != NULL) { // clean up if MPI call fails
        delete comm_;
        comm_ = NULL;
      }
      TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
        "Teuchos::DefaultComm::getComm: MPI_Comm_create_keyval failed!");
    }
    int val = key; // doesn't matter

    // Attach the attribute to MPI_COMM_SELF.
    err = MPI_Comm_set_attr (MPI_COMM_SELF, key, &val);
    if (err != MPI_SUCCESS) {
      // MPI (versions up to and including 3.0) doesn't promise
      // correct behavior after any function returns something other
      // than MPI_SUCCESS.  Thus, it's not required to try to free the
      // new key via MPI_Comm_free_keyval.  Furthermore, if something
      // went wrong with MPI_Comm_set_attr, it's likely that the
      // attribute mechanism is broken.  Thus, it would be unwise to
      // call MPI_Comm_free_keyval.  However, we can still clean up
      // other data.
      if (comm_ != NULL) { // clean up if MPI call fails
        delete comm_;
        comm_ = NULL;
      }
      TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
        "Teuchos::DefaultComm::getComm: MPI_Comm_set_attr failed!");
    }

    // It looks weird to "free" the key right away.  However, this
    // does not actually cause the "destructor" to be called.  It only
    // gets called at MPI_FINALIZE.  See MPI 3.0 standard, Section
    // 6.7.2, MPI_COMM_FREE_KEYVAL:
    //
    // "Note that it is not erroneous to free an attribute key that is
    // in use, because the actual free does not transpire until after
    // all references (in other communicators on the process) to the
    // key have been freed.  These references need to be explicitly
    // freed by the program, either via calls to MPI_COMM_DELETE_ATTR
    // that free one attribute instance, or by calls to MPI_COMM_FREE
    // that free all attribute instances associated with the freed
    // communicator."
    //
    // We rely here on the latter mechanism.  MPI_FINALIZE calls
    // MPI_COMM_FREE on MPI_COMM_SELF, so we do not need to call it
    // explicitly.
    //
    // It's not clear what to do if the MPI_* calls above succeeded,
    // but this call fails (i.e., returns != MPI_SUCCESS).  We could
    // throw; this would make sense to do, because MPI (versions up to
    // and including 3.0) doesn't promise correct behavior after any
    // MPI function returns something other than MPI_SUCCESS.  We
    // could also be optimistic and just ignore the return value,
    // hoping that if the above calls succeeded, then the communicator
    // will get freed at MPI_FINALIZE, even though the unfreed key may
    // leak memory (see Bug 6338).  I've chosen the latter.
    (void) MPI_Comm_free_keyval (&key);

#  else // MPI_VERSION < 2
#    error "Sorry, you need an MPI implementation that supports at least MPI 2.0 in order to build this code.  MPI 2.0 came out in 1997.  I wrote this comment in 2017.  If you really _really_ want MPI 1.x support, please file a GitHub issue for this feature request at github.com/trilinos/trilinos/issues with an expression of its priority and we will get to it as soon as we can."
#  endif // MPI_VERSION >= 2

#else // NOT HAVE_MPI
    comm_ = new SerialComm<OrdinalType> ();
    // We want comm_ to be deallocated when main exits, so register
    // its deallocation function as an atexit handler.
    //
    // The POSIX standard allows atexit to fail, in particular if it
    // lacks space for registering more functions.  "[T]he application
    // should call sysconf() to obtain the value of {ATEXIT_MAX}, the
    // [maximum] number of functions that can be registered. There is
    // no way for an application to tell how many functions have
    // already been registered with atexit()."
    //
    // We don't do this here.  Instead, we just check atexit's return
    // code.  If it fails, we throw.
    int err = atexit (freeDefaultComm);
    if (err != 0) {
      if (comm_ != NULL) { // clean up if atexit fails
        delete comm_;
        comm_ = NULL;
      }
      TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
        "Teuchos::DefaultComm::getComm: atexit failed!");
    }
#endif // HAVE_MPI
  }

  TEUCHOS_TEST_FOR_EXCEPTION
    (comm_ == NULL, std::logic_error, "Teuchos::DefaultComm::getComm: "
     "comm_ == NULL before return.  This should never happen.  "
     "Please report this bug to the Teuchos developers.");

  // Return a nonowning RCP, because we need to ensure that
  // destruction happens at MPI_Finalize (or at exit of main(), if not
  // building with MPI).
  return rcp (comm_, false);
}

template<typename OrdinalType>
Teuchos::RCP<const Teuchos::Comm<OrdinalType> >
DefaultComm<OrdinalType>::
getDefaultSerialComm (const Teuchos::RCP<const Comm<OrdinalType> >& comm)
{
  if (! comm.is_null ()) {
    return comm;
  } else {
    if (defaultSerialComm_ == NULL) {
#ifdef HAVE_MPI
#  if MPI_VERSION >= 2
      //defaultSerialComm_ = new MpiComm<OrdinalType> (MPI_COMM_SELF);
      defaultSerialComm_ = new SerialComm<OrdinalType> ();

      // Register an MPI_Finalize hook to free defaultSerialComm_.
      // (See getComm implementation above in this file for details.)

      int key = MPI_KEYVAL_INVALID;
      int err =
        MPI_Comm_create_keyval (MPI_COMM_NULL_COPY_FN,
                                Details::mpiFreeDefaultSerialComm<OrdinalType>,
                                &key,
                                NULL); // no extra state
      if (err != MPI_SUCCESS) {
        if (defaultSerialComm_ != NULL) { // clean up if MPI call fails
          delete defaultSerialComm_;
          defaultSerialComm_ = NULL;
        }
        TEUCHOS_TEST_FOR_EXCEPTION(
          true, std::runtime_error, "Teuchos::DefaultComm::getDefaultSerialComm"
          ": MPI_Comm_create_keyval failed!");
      }
      int val = key; // doesn't matter

      // Attach the attribute to MPI_COMM_SELF.
      err = MPI_Comm_set_attr (MPI_COMM_SELF, key, &val);
      if (err != MPI_SUCCESS) {
        // See comments in getComm implementation above to see why we
        // don't call MPI_Comm_free_keyval here.
        if (defaultSerialComm_ != NULL) { // clean up if MPI call fails
          delete defaultSerialComm_;
          defaultSerialComm_ = NULL;
        }
        TEUCHOS_TEST_FOR_EXCEPTION(
          true, std::runtime_error, "Teuchos::DefaultComm::getDefaultSerialComm"
          ": MPI_Comm_set_attr failed!");
      }

      // See comments in getComm implementation above to see why we
      // _do_ call MPI_Comm_free_keyval here, and why we don't check
      // the return code.
      (void) MPI_Comm_free_keyval (&key);

#  else // MPI_VERSION < 2
#    error "Sorry, you need an MPI implementation that supports at least MPI 2.0 in order to build this code.  MPI 2.0 came out in 1997.  I wrote this comment in 2017.  If you really _really_ want MPI 1.x support, please file a GitHub issue for this feature request at github.com/trilinos/trilinos/issues with an expression of its priority and we will get to it as soon as we can."
#  endif // MPI_VERSION >= 2

#else // NOT HAVE_MPI
      defaultSerialComm_ = new SerialComm<OrdinalType> ();
      // We want defaultSerialComm_ to be deallocated when main exits,
      // so register its deallocation function as an atexit handler.
      //
      // The POSIX standard allows atexit to fail, in particular if it
      // lacks space for registering more functions.  "[T]he
      // application should call sysconf() to obtain the value of
      // {ATEXIT_MAX}, the [maximum] number of functions that can be
      // registered. There is no way for an application to tell how
      // many functions have already been registered with atexit()."
      //
      // We don't do this here.  Instead, we just check atexit's
      // return code.  If it fails, we throw.
      int err = atexit (freeDefaultComm);
      if (err != 0) {
        if (defaultSerialComm_ != NULL) { // clean up if atexit fails
          delete defaultSerialComm_;
          defaultSerialComm_ = NULL;
        }
        TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
          "Teuchos::DefaultComm::getDefaultSerialComm: atexit failed!");
      }
#endif // HAVE_MPI
    }

    TEUCHOS_TEST_FOR_EXCEPTION
      (defaultSerialComm_ == NULL, std::logic_error, "Teuchos::DefaultComm::"
       "getDefaultSerialComm: defaultSerialComm_ == NULL before return.  This sh"
       "ould never happen.  Please report this bug to the Teuchos developers.");

    // Return a nonowning RCP, because we need to ensure that
    // destruction happens at MPI_Finalize (or at exit of main(), if not
    // building with MPI).
    return rcp (defaultSerialComm_, false);
  }
}

template<typename OrdinalType>
const Teuchos::Comm<OrdinalType>*
DefaultComm<OrdinalType>::comm_ = NULL;

template<typename OrdinalType>
const Teuchos::Comm<OrdinalType>*
DefaultComm<OrdinalType>::defaultSerialComm_ = NULL;

} // namespace Teuchos

#endif // TEUCHOS_DEFAULT_COMM_HPP