1 /******************************************************************************
2  * Copyright 1998-2019 Lawrence Livermore National Security, LLC and other
3  * HYPRE Project Developers. See the top-level COPYRIGHT file for details.
4  *
5  * SPDX-License-Identifier: (Apache-2.0 OR MIT)
6  ******************************************************************************/
7 
8 /* see exchange_data.README for additional information */
9 /* AHB 6/04 */
10 
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <math.h>
14 
15 #include "_hypre_utilities.h"
16 
17 /*---------------------------------------------------
18  * hypre_CreateBinaryTree()
19  * Get the processors position in the binary tree (i.e.,
20  * its children and parent processor ids)
21  *----------------------------------------------------*/
22 
hypre_CreateBinaryTree(HYPRE_Int myid,HYPRE_Int num_procs,hypre_BinaryTree * tree)23 HYPRE_Int hypre_CreateBinaryTree(HYPRE_Int myid, HYPRE_Int num_procs,
24                                  hypre_BinaryTree *tree)
25 {
26    HYPRE_Int  i, proc, size=0;
27    HYPRE_Int  *tmp_child_id;
28    HYPRE_Int  num=0, parent = 0;
29 
30    /* initialize*/
31    proc = myid;
32 
33    /*how many children can a processor have?*/
34    for (i = 1; i < num_procs; i *= 2)
35    {
36       size++;
37    }
38 
39    /* allocate space */
40    tmp_child_id = hypre_TAlloc(HYPRE_Int,  size, HYPRE_MEMORY_HOST);
41 
42    /* find children and parent */
43    for (i = 1; i < num_procs; i *= 2)
44    {
45       if ( (proc % 2) == 0)
46       {
47          if( (myid + i) < num_procs )
48          {
49             tmp_child_id[num] = myid + i;
50             num++;
51          }
52          proc /= 2;
53       }
54       else
55       {
56          parent = myid - i;
57          break;
58       }
59 
60    }
61 
62    hypre_BinaryTreeParentId(tree) = parent;
63    hypre_BinaryTreeNumChild(tree) = num;
64    hypre_BinaryTreeChildIds(tree) = tmp_child_id;
65 
66    return hypre_error_flag;
67 }
68 
69 /*---------------------------------------------------
70  * hypre_DestroyBinaryTree()
71  * Destroy storage created by createBinaryTree
72  *----------------------------------------------------*/
hypre_DestroyBinaryTree(hypre_BinaryTree * tree)73 HYPRE_Int hypre_DestroyBinaryTree(hypre_BinaryTree *tree)
74 {
75 
76    hypre_TFree(hypre_BinaryTreeChildIds(tree), HYPRE_MEMORY_HOST);
77 
78    return hypre_error_flag;
79 }
80 
81 /*---------------------------------------------------
82  * hypre_DataExchangeList()
83  * This function is for sending a list of messages ("contacts" to
84  * a list of processors.  The receiving processors
85  * do not know how many messages they are getting. The
86  * sending process expects a "response" (either a confirmation or
87  * some sort of data back from the receiving processor).
88  *----------------------------------------------------*/
89 
90 /* should change to where the buffers for sending and receiving are voids
91    instead of ints - then cast accordingly */
92 
hypre_DataExchangeList(HYPRE_Int num_contacts,HYPRE_Int * contact_proc_list,void * contact_send_buf,HYPRE_Int * contact_send_buf_starts,HYPRE_Int contact_obj_size,HYPRE_Int response_obj_size,hypre_DataExchangeResponse * response_obj,HYPRE_Int max_response_size,HYPRE_Int rnum,MPI_Comm comm,void ** p_response_recv_buf,HYPRE_Int ** p_response_recv_buf_starts)93 HYPRE_Int hypre_DataExchangeList(HYPRE_Int num_contacts,
94                                  HYPRE_Int *contact_proc_list,
95                                  void *contact_send_buf,
96                                  HYPRE_Int *contact_send_buf_starts,
97                                  HYPRE_Int contact_obj_size,
98                                  HYPRE_Int response_obj_size,
99                                  hypre_DataExchangeResponse *response_obj,
100                                  HYPRE_Int max_response_size,
101                                  HYPRE_Int rnum, MPI_Comm comm,
102                                  void **p_response_recv_buf,
103                                  HYPRE_Int **p_response_recv_buf_starts)
104 {
105    /*-------------------------------------------
106     *  parameters:
107     *
108     *    num_contacts              = how many procs to contact
109     *    contact_proc_list         = list of processors to contact
110     *    contact_send_buf          = array of data to send
111     *    contact_send_buf_starts   = index for contact_send_buf corresponding to
112     *                                contact_proc_list
113     *    contact_obj_size          = sizeof() one obj in contact list
114 
115     *    response_obj_size          = sizeof() one obj in response_recv_buf
116     *    response_obj              = this will give us the function we need to
117     *                                fill the reponse as well as
118     *                                any data we might need to accomplish that
119     *    max_response_size         = max size of a single response expected (do NOT
120     *                                need to be an absolute upper bound)
121     *    rnum                      = two consequentive exchanges should have different
122     *                                rnums. Alternate rnum = 1
123     *                                and rnum=2  - these flags will be even (so odd
124     *                                numbered tags could be used in calling code)
125     *    p_response_recv_buf       = where to receive the reponses - will be allocated
126     *                                in this function
127     *    p_response_recv_buf_starts  = index of p_response_buf corresponding to
128     *                                contact_buf_list - will be allocated here
129 
130     *-------------------------------------------*/
131 
132    HYPRE_Int  num_procs, myid;
133    HYPRE_Int  i;
134    HYPRE_Int  terminate, responses_complete;
135    HYPRE_Int  children_complete;
136    HYPRE_Int  contact_flag;
137    HYPRE_Int  proc;
138    HYPRE_Int  contact_size;
139 
140    HYPRE_Int  size, post_size, copy_size;
141    HYPRE_Int  total_size, count;
142 
143    void *start_ptr = NULL, *index_ptr=NULL;
144    HYPRE_Int  *int_ptr=NULL;
145 
146    void *response_recv_buf = NULL;
147    void *send_response_buf = NULL;
148 
149    HYPRE_Int  *response_recv_buf_starts = NULL;
150    void *initial_recv_buf = NULL;
151 
152    void *recv_contact_buf = NULL;
153    HYPRE_Int  recv_contact_buf_size = 0;
154 
155    HYPRE_Int  response_message_size = 0;
156 
157    HYPRE_Int  overhead;
158 
159    HYPRE_Int  max_response_size_bytes;
160 
161    HYPRE_Int  max_response_total_bytes;
162 
163    void **post_array = NULL;  /*this must be set to null or realloc will crash */
164    HYPRE_Int  post_array_storage = 0;
165    HYPRE_Int  post_array_size = 0;
166    HYPRE_Int   num_post_recvs =0;
167 
168    void **contact_ptrs = NULL, **response_ptrs=NULL, **post_ptrs=NULL;
169 
170    hypre_BinaryTree tree;
171 
172    hypre_MPI_Request *response_requests, *contact_requests;
173    hypre_MPI_Status  *response_statuses, *contact_statuses;
174 
175    hypre_MPI_Request  *post_send_requests = NULL, *post_recv_requests = NULL;
176    hypre_MPI_Status   *post_send_statuses = NULL, *post_recv_statuses = NULL;
177 
178    hypre_MPI_Request *term_requests, term_request1, request_parent;
179    hypre_MPI_Status  *term_statuses, term_status1, status_parent;
180    hypre_MPI_Status  status, fill_status;
181 
182    const HYPRE_Int contact_tag = 1000*rnum;
183    const HYPRE_Int response_tag = 1002*rnum;
184    const HYPRE_Int term_tag =  1004*rnum;
185    const HYPRE_Int post_tag = 1006*rnum;
186 
187    hypre_MPI_Comm_size(comm, &num_procs );
188    hypre_MPI_Comm_rank(comm, &myid );
189 
190    /* ---------initializations ----------------*/
191 
192    /* if the response_obj_size or contact_obj_size is 0, set to sizeof(HYPRE_Int) */
193    if (!response_obj_size) response_obj_size = sizeof(HYPRE_Int);
194    if (!contact_obj_size) contact_obj_size = sizeof(HYPRE_Int);
195 
196    max_response_size_bytes = max_response_size*response_obj_size;
197 
198 
199    /* pre-allocate the max space for responding to contacts */
200    overhead = ceil((HYPRE_Real) sizeof(HYPRE_Int)/response_obj_size); /*for appending an integer*/
201 
202    max_response_total_bytes = (max_response_size+overhead)*response_obj_size;
203 
204    response_obj->send_response_overhead = overhead;
205    response_obj->send_response_storage = max_response_size;
206 
207    /*send_response_buf = hypre_MAlloc(max_response_total_bytes);*/
208    send_response_buf = hypre_CTAlloc(char, (max_response_size+overhead)*response_obj_size, HYPRE_MEMORY_HOST);
209 
210    /*allocate space for inital recv array for the responses - give each processor
211      size max_response_size */
212 
213    initial_recv_buf = hypre_TAlloc(char, max_response_total_bytes*num_contacts, HYPRE_MEMORY_HOST);
214    response_recv_buf_starts =   hypre_CTAlloc(HYPRE_Int,  num_contacts+1, HYPRE_MEMORY_HOST);
215 
216    contact_ptrs = hypre_TAlloc( void *,  num_contacts, HYPRE_MEMORY_HOST);
217    response_ptrs = hypre_TAlloc(void *,  num_contacts, HYPRE_MEMORY_HOST);
218 
219    /*-------------SEND CONTACTS AND POST RECVS FOR RESPONSES---*/
220 
221    for (i=0; i<= num_contacts; i++)
222    {
223       response_recv_buf_starts[i] = i*(max_response_size+overhead);
224    }
225 
226    /* Send "contact" messages to the list of processors and
227       pre-post receives to wait for their response*/
228 
229    responses_complete = 1;
230    if (num_contacts > 0 )
231    {
232       responses_complete = 0;
233       response_requests = hypre_CTAlloc(hypre_MPI_Request,  num_contacts, HYPRE_MEMORY_HOST);
234       response_statuses = hypre_CTAlloc(hypre_MPI_Status,  num_contacts, HYPRE_MEMORY_HOST);
235       contact_requests = hypre_CTAlloc(hypre_MPI_Request,  num_contacts, HYPRE_MEMORY_HOST);
236       contact_statuses = hypre_CTAlloc(hypre_MPI_Status,  num_contacts, HYPRE_MEMORY_HOST);
237 
238       /* post receives - could be confirmation or data*/
239       /* the size to post is max_response_total_bytes*/
240 
241       for (i=0; i< num_contacts; i++)
242       {
243          /* response_ptrs[i] =  initial_recv_buf + i*max_response_total_bytes ; */
244          response_ptrs[i] = (void *)((char *) initial_recv_buf +
245                                      i*max_response_total_bytes) ;
246 
247          hypre_MPI_Irecv(response_ptrs[i], max_response_total_bytes,
248                          hypre_MPI_BYTE, contact_proc_list[i],
249                          response_tag, comm, &response_requests[i]);
250       }
251 
252       /* send out contact messages */
253       start_ptr = contact_send_buf;
254       for (i=0; i< num_contacts; i++)
255       {
256          contact_ptrs[i] = start_ptr;
257          size =  contact_send_buf_starts[i+1] - contact_send_buf_starts[i]  ;
258          hypre_MPI_Isend(contact_ptrs[i], size*contact_obj_size,
259                          hypre_MPI_BYTE, contact_proc_list[i],
260                          contact_tag, comm, &contact_requests[i]);
261          /*  start_ptr += (size*contact_obj_size); */
262          start_ptr = (void *) ((char *) start_ptr  + (size*contact_obj_size));
263       }
264    }
265 
266    /*------------BINARY TREE-----------------------*/
267 
268    /*Now let's find out our binary tree information and
269      initialize for the termination check sweep */
270    terminate = 1; /*indicates whether we can stop probing for contact */
271    children_complete = 1;/*indicates whether we have recv. term messages
272                            from our children*/
273 
274    if (num_procs > 1)
275    {
276       hypre_CreateBinaryTree(myid, num_procs, &tree);
277 
278       /* we will get a message from all of our children when they
279          have received responses for all of their contacts.
280          So post receives now */
281 
282       term_requests = hypre_CTAlloc(hypre_MPI_Request,  tree.num_child, HYPRE_MEMORY_HOST);
283       term_statuses = hypre_CTAlloc(hypre_MPI_Status,  tree.num_child, HYPRE_MEMORY_HOST);
284 
285       for (i=0; i< tree.num_child; i++)
286       {
287 	 hypre_MPI_Irecv(NULL, 0, HYPRE_MPI_INT, tree.child_id[i], term_tag, comm,
288                          &term_requests[i]);
289       }
290 
291       terminate = 0;
292 
293       children_complete = 0;
294    }
295    else if (num_procs ==1 && num_contacts > 0 ) /* added 11/08 */
296    {
297       terminate = 0;
298    }
299 
300    /*---------PROBE LOOP-----------------------------------------*/
301 
302    /*Look for incoming contact messages - don't know how many I will get!*/
303 
304    while (!terminate)
305    {
306       /* did I receive any contact messages? */
307       hypre_MPI_Iprobe(hypre_MPI_ANY_SOURCE, contact_tag, comm,
308                        &contact_flag, &status);
309 
310       while (contact_flag)
311       {
312          /* received contacts - from who and what do we do ?*/
313          proc = status.hypre_MPI_SOURCE;
314          hypre_MPI_Get_count(&status, hypre_MPI_BYTE, &contact_size);
315 
316          contact_size = contact_size/contact_obj_size;
317 
318          /*---------------FILL RESPONSE ------------------------*/
319 
320          /*first receive the contact buffer - then call a function
321            to determine how to populate the send buffer for the reponse*/
322 
323          /* do we have enough space to recv it? */
324          if(contact_size > recv_contact_buf_size)
325          {
326             recv_contact_buf = hypre_TReAlloc((char*)recv_contact_buf,
327                                               char, contact_obj_size*contact_size, HYPRE_MEMORY_HOST);
328             recv_contact_buf_size = contact_size;
329          }
330 
331          /* this must be blocking - can't fill recv without the buffer*/
332          hypre_MPI_Recv(recv_contact_buf, contact_size*contact_obj_size,
333                         hypre_MPI_BYTE, proc, contact_tag, comm, &fill_status);
334 
335          response_obj->fill_response(recv_contact_buf, contact_size, proc,
336                                      response_obj, comm, &send_response_buf,
337                                      &response_message_size );
338 
339          /* we need to append the size of the send obj */
340          /* first we copy out any part that may be needed to send later so we don't overwrite */
341          post_size = response_message_size - max_response_size;
342          if (post_size > 0) /*we will need to send the extra information later */
343          {
344             /*hypre_printf("myid = %d, post_size = %d\n", myid, post_size);*/
345 
346             if (post_array_size == post_array_storage)
347 
348             {
349                /* allocate room for more posts  - add 20*/
350                post_array_storage += 20;
351                post_array = hypre_TReAlloc(post_array,  void *,  post_array_storage, HYPRE_MEMORY_HOST);
352                post_send_requests =
353                   hypre_TReAlloc(post_send_requests,  hypre_MPI_Request,
354                                  post_array_storage, HYPRE_MEMORY_HOST);
355             }
356             /* allocate space for the data this post only*/
357             /* this should not happen often (unless a poor max_size has been chosen)
358                - so we will allocate space for the data as needed */
359             size = post_size*response_obj_size;
360             post_array[post_array_size] =  hypre_TAlloc(char, size, HYPRE_MEMORY_HOST);
361             /* index_ptr =  send_response_buf + max_response_size_bytes */;
362             index_ptr = (void *) ((char *) send_response_buf +
363                                   max_response_size_bytes);
364 
365             hypre_TMemcpy(post_array[post_array_size], index_ptr, char,  size, HYPRE_MEMORY_HOST, HYPRE_MEMORY_HOST);
366 
367             /*now post any part of the message that is too long with a non-blocking
368               send and a different tag */
369 
370             hypre_MPI_Isend(post_array[post_array_size], size,
371                             hypre_MPI_BYTE, proc, post_tag,
372                             /*hypre_MPI_COMM_WORLD, */
373                             comm,
374                             &post_send_requests[post_array_size]);
375 
376             post_array_size++;
377          }
378 
379          /*now append the size information into the overhead storage */
380          /* index_ptr =  send_response_buf + max_response_size_bytes; */
381          index_ptr = (void *) ((char *) send_response_buf +
382                                max_response_size_bytes);
383 
384          hypre_TMemcpy(index_ptr,  &response_message_size, HYPRE_Int, 1, HYPRE_MEMORY_HOST, HYPRE_MEMORY_HOST);
385 
386          /*send the block of data that includes the overhead */
387          /* this is a blocking send - the recv has already been posted */
388          hypre_MPI_Send(send_response_buf, max_response_total_bytes,
389                         hypre_MPI_BYTE, proc, response_tag, comm);
390 
391          /*--------------------------------------------------------------*/
392 
393          /* look for any more contact messages*/
394          hypre_MPI_Iprobe(hypre_MPI_ANY_SOURCE, contact_tag, comm,
395                           &contact_flag, &status);
396       }
397 
398       /* no more contact messages waiting - either
399          (1) check to see if we have received all of our response messages
400          (2) participate in termination (check for messages from children)
401          (3) participate in termination sweep (check for message from parent) */
402 
403       if (!responses_complete)
404       {
405          hypre_MPI_Testall(num_contacts, response_requests, &responses_complete,
406                            response_statuses);
407          if (responses_complete && num_procs == 1) terminate = 1; /*added 11/08 */
408 
409       }
410       else if(!children_complete) /* have all of our children received all of their
411                                      response messages?*/
412       {
413          hypre_MPI_Testall(tree.num_child, term_requests, &children_complete,
414                            term_statuses);
415 
416          /* if we have gotten term messages from all of our children, send a term
417             message to our parent.  Then post a receive to hear back from parent */
418 	 if (children_complete & (myid > 0)) /*root does not have a parent*/
419          {
420             hypre_MPI_Isend(NULL, 0, HYPRE_MPI_INT, tree.parent_id, term_tag,
421                             comm, &request_parent);
422 
423             hypre_MPI_Irecv(NULL, 0, HYPRE_MPI_INT, tree.parent_id, term_tag,
424                             comm, &term_request1);
425          }
426       }
427       else /*have we gotten a term message from our parent? */
428       {
429          if (myid == 0) /* root doesn't have a parent */
430          {
431             terminate = 1;
432          }
433          else
434          {
435             hypre_MPI_Test(&term_request1, &terminate, &term_status1);
436          }
437          if (terminate) /*tell children to terminate */
438 	 {
439             if (myid > 0 ) hypre_MPI_Wait(&request_parent, &status_parent);
440 
441 	    for (i=0; i< tree.num_child; i++)
442 	    {  /*a blocking send  - recv has been posted already*/
443 	       hypre_MPI_Send(NULL, 0, HYPRE_MPI_INT, tree.child_id[i],
444                               term_tag, comm);
445 	    }
446 	 }
447       }
448    }
449 
450    /* end of (!terminate) loop */
451 
452    /* ----some clean up before post-processing ----*/
453    if (recv_contact_buf_size > 0)
454    {
455       hypre_TFree(recv_contact_buf, HYPRE_MEMORY_HOST);
456    }
457 
458    hypre_TFree(send_response_buf, HYPRE_MEMORY_HOST);
459    hypre_TFree(contact_ptrs, HYPRE_MEMORY_HOST);
460    hypre_TFree(response_ptrs, HYPRE_MEMORY_HOST);
461 
462    /*-----------------POST PROCESSING------------------------------*/
463 
464    /* more data to receive? */
465    /* move to recv buffer and update response_recv_buf_starts */
466 
467    total_size = 0;  /*total number of items in response buffer */
468    num_post_recvs = 0; /*num of post processing recvs to post */
469    start_ptr = initial_recv_buf;
470    response_recv_buf_starts[0] = 0; /*already allocated above */
471 
472    /*an extra loop to determine sizes.  This is better than reallocating
473      the array that will be used in posting the irecvs */
474    for (i=0; i< num_contacts; i++)
475    {
476       int_ptr = (HYPRE_Int *) ((char *) start_ptr + max_response_size_bytes); /*the overhead HYPRE_Int*/
477 
478       response_message_size =  *int_ptr;
479       response_recv_buf_starts[i+1] =
480          response_recv_buf_starts[i] + response_message_size;
481       total_size +=  response_message_size;
482       if (max_response_size < response_message_size) num_post_recvs++;
483       /* start_ptr += max_response_total_bytes; */
484       start_ptr = (void *) ((char *) start_ptr + max_response_total_bytes);
485    }
486 
487    post_recv_requests = hypre_TAlloc(hypre_MPI_Request,  num_post_recvs, HYPRE_MEMORY_HOST);
488    post_recv_statuses = hypre_TAlloc(hypre_MPI_Status,  num_post_recvs, HYPRE_MEMORY_HOST);
489    post_ptrs = hypre_TAlloc(void *,  num_post_recvs, HYPRE_MEMORY_HOST);
490 
491    /*second loop to post any recvs and set up recv_response_buf */
492    response_recv_buf = hypre_TAlloc(char, total_size*response_obj_size, HYPRE_MEMORY_HOST);
493    index_ptr = response_recv_buf;
494    start_ptr = initial_recv_buf;
495    count = 0;
496 
497    for (i=0; i< num_contacts; i++)
498    {
499       response_message_size =
500          response_recv_buf_starts[i+1] - response_recv_buf_starts[i];
501       copy_size = hypre_min(response_message_size, max_response_size);
502 
503       hypre_TMemcpy(index_ptr,  start_ptr,  char, copy_size*response_obj_size, HYPRE_MEMORY_HOST, HYPRE_MEMORY_HOST);
504       /* index_ptr += copy_size*response_obj_size; */
505       index_ptr = (void *) ((char *) index_ptr + copy_size*response_obj_size);
506 
507       if (max_response_size < response_message_size)
508       {
509          size = (response_message_size - max_response_size)*response_obj_size;
510          post_ptrs[count] = index_ptr;
511          hypre_MPI_Irecv(post_ptrs[count], size, hypre_MPI_BYTE,
512                          contact_proc_list[i], post_tag,
513                          comm, &post_recv_requests[count]);
514          count++;
515          /* index_ptr+=size;*/
516          index_ptr=  (void *) ((char *) index_ptr + size);
517       }
518 
519       /* start_ptr += max_response_total_bytes; */
520       start_ptr = (void *) ((char *) start_ptr + max_response_total_bytes);
521    }
522 
523    post_send_statuses = hypre_TAlloc(hypre_MPI_Status,  post_array_size, HYPRE_MEMORY_HOST);
524 
525    /*--------------CLEAN UP------------------- */
526 
527    hypre_TFree(initial_recv_buf, HYPRE_MEMORY_HOST);
528 
529    if (num_contacts > 0 )
530    {
531       /*these should be done */
532       hypre_MPI_Waitall(num_contacts, contact_requests, contact_statuses);
533 
534       hypre_TFree(response_requests, HYPRE_MEMORY_HOST);
535       hypre_TFree(response_statuses, HYPRE_MEMORY_HOST);
536       hypre_TFree(contact_requests, HYPRE_MEMORY_HOST);
537       hypre_TFree(contact_statuses, HYPRE_MEMORY_HOST);
538    }
539 
540    /* clean up from the post processing - the arrays, requests, etc. */
541 
542    if (num_post_recvs)
543    {
544       hypre_MPI_Waitall(num_post_recvs, post_recv_requests, post_recv_statuses);
545       hypre_TFree(post_recv_requests, HYPRE_MEMORY_HOST);
546       hypre_TFree(post_recv_statuses, HYPRE_MEMORY_HOST);
547       hypre_TFree(post_ptrs, HYPRE_MEMORY_HOST);
548    }
549 
550    if (post_array_size)
551    {
552       hypre_MPI_Waitall(post_array_size, post_send_requests, post_send_statuses);
553 
554       hypre_TFree(post_send_requests, HYPRE_MEMORY_HOST);
555       hypre_TFree(post_send_statuses, HYPRE_MEMORY_HOST);
556 
557       for (i=0; i< post_array_size; i++)
558       {
559          hypre_TFree(post_array[i], HYPRE_MEMORY_HOST);
560       }
561       hypre_TFree(post_array, HYPRE_MEMORY_HOST);
562    }
563 
564    if (num_procs > 1)
565    {
566       hypre_TFree(term_requests, HYPRE_MEMORY_HOST);
567       hypre_TFree(term_statuses, HYPRE_MEMORY_HOST);
568 
569       hypre_DestroyBinaryTree(&tree);
570    }
571 
572    /* output  */
573    *p_response_recv_buf = response_recv_buf;
574    *p_response_recv_buf_starts = response_recv_buf_starts;
575 
576    return hypre_error_flag;
577 }
578