mpipack.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * mpipack.c
  3. *
  4. * Packing stuff into buffers for cross-PE communication
  5. */
  6. /* Signature: 6868fcef 19-Aug-1998 */
  7. #ifndef header_mpipack_h
  8. #define header_mpipack_h
  9. /* Code to pack a Lisp cons-structure into a linear buffer and retrieve it. */
  10. /* These are the calls to do it; think of them as
  11. * void pack_object(Lisp_Object a);
  12. * and Lisp_Object unpack_object();
  13. */
  14. #define pack_object(a) (mpi_pack_buffer = 0, \
  15. mpi_pack_position = 0, \
  16. mpi_pack_size = 0, \
  17. pack_cell(a) )
  18. /* Once a message has been packed, it may be sent using mpi_pack_buffer and
  19. * mpi_pack_position as the "buf" and "count" fields, and MPI_PACKED as the
  20. * Datatype.
  21. */
  22. /* mpi_pack_buffer should be set to the recieve buffer before calling this. */
  23. #define unpack_object() (mpi_pack_position = 0, unpack_cell())
  24. /* There must be a buffer to put them in.
  25. * It will grow by MPI_BUFFER_BLOCK bytes at a time, as needed.
  26. */
  27. static char* mpi_pack_buffer = 0;
  28. static int mpi_pack_size = 0;
  29. #define MPI_BUFFER_BLOCK 1024
  30. /* position marker for MPI_(Un)Pack */
  31. static int mpi_pack_position = 0;
  32. /* THE REST OF THIS FILE IS PRIVATE */
  33. /* Function to check the size of the buffer, and grow it if necessary.
  34. * check_buffer(n) will make sure that there are n free bytes in the buffer.
  35. */
  36. static void default_check_buffer(int n)
  37. {
  38. if (mpi_pack_size - mpi_pack_position < n){
  39. mpi_pack_size += MPI_BUFFER_BLOCK;
  40. mpi_pack_buffer = (char*)realloc( mpi_pack_buffer, mpi_pack_size);
  41. if (mpi_pack_buffer == 0) aerror0("Not enough memory for MPI buffer.");
  42. }
  43. }
  44. static char* mpi_buffer_bottom;
  45. static int mpi_pack_offset;
  46. static int mpi_real_size;
  47. static void scatter_check_buffer(int n)
  48. {
  49. if (mpi_real_size - ( (mpi_pack_buffer - mpi_buffer_bottom) +
  50. mpi_pack_position ) < n) {
  51. mpi_real_size += MPI_BUFFER_BLOCK;
  52. mpi_pack_size += MPI_BUFFER_BLOCK;
  53. mpi_buffer_bottom = (char*)realloc( mpi_buffer_bottom, mpi_real_size);
  54. if (mpi_buffer_bottom == 0) aerror0("Not enough memory for MPI buffer.");
  55. mpi_pack_buffer = mpi_buffer_bottom + mpi_pack_offset;
  56. }
  57. }
  58. typedef void buffptr(int);
  59. static buffptr *check_buffer = default_check_buffer;
  60. /* MPI insists on using pointers everywhere, so here are things to point at. */
  61. static char mpi_packing_symbols[] = {' ', '(', ')', '.', ','};
  62. static Lisp_Object mpi_pack_number;
  63. static char mpi_pack_char;
  64. /* The MPI function calls for packing */
  65. /* Think of this as void pack_32bit(Lisp_Object),but it actually returns int */
  66. /* The name is to remind one that the size is fixed for now. It would be
  67. * better to conditionally define a type of either MPI_LONG or MPI_LONG_LONG
  68. * depending on the size of Lisp objects. This may happen eventually.
  69. */
  70. #define pack_32bit(n) (check_buffer(4), \
  71. MPI_Pack(&(n), 1, MPI_UNSIGNED_LONG, \
  72. mpi_pack_buffer, mpi_pack_size, \
  73. &mpi_pack_position, MPI_COMM_WORLD) )
  74. /* The functions to flatten the list structures, according to a simple grammar*/
  75. static void pack_list(Lisp_Object a);
  76. static void pack_cell(Lisp_Object a);
  77. static void pack_atom(Lisp_Object a)
  78. {
  79. if (is_fixnum(a)) pack_32bit(a);
  80. else if (is_bfloat(a)) {
  81. Header* h = &flthdr(a);
  82. if (type_of_header(*h) == TYPE_DOUBLE_FLOAT){
  83. pack_32bit(*h);
  84. check_buffer(sizeof(double));
  85. MPI_Pack( &(((Double_Float*)h)->f), 1, MPI_DOUBLE,
  86. mpi_pack_buffer, mpi_pack_size,
  87. &mpi_pack_position, MPI_COMM_WORLD);
  88. }
  89. else err_printf("Unsupported float type %x\n",type_of_header(*h));
  90. }
  91. else if (is_numbers(a)) {
  92. Header* h = &numhdr(a);
  93. int size = length_of_header(*h) - sizeof(Header);
  94. if (type_of_header(*h) == TYPE_BIGNUM){
  95. pack_32bit(*h);
  96. /* Bignums are arrays of 32-bit things; we'll have to pack them
  97. as such to avoid byte-ordering problems. */
  98. check_buffer(size);
  99. MPI_Pack(h+1, size >> 2, MPI_UNSIGNED_LONG,
  100. mpi_pack_buffer, mpi_pack_size, &mpi_pack_position,
  101. MPI_COMM_WORLD);
  102. }
  103. else err_printf("Unsupported number type %x\n",type_of_header(*h));
  104. }
  105. else if (is_vector(a)) {
  106. Header* h = &vechdr(a);
  107. switch(type_of_header(*h)){
  108. case TYPE_STRING:
  109. pack_32bit(*h);
  110. {
  111. int size = length_of_header(*h) - sizeof(Header);
  112. check_buffer(size);
  113. MPI_Pack(h+1, size, MPI_CHAR,
  114. mpi_pack_buffer, mpi_pack_size,
  115. &mpi_pack_position, MPI_COMM_WORLD);
  116. }
  117. break;
  118. case TYPE_SIMPLE_VEC: case TYPE_ARRAY: case TYPE_STRUCTURE:
  119. pack_32bit(*h);
  120. {
  121. int i;
  122. for (i = 0; i < (length_of_header(*h)>>2) - 1; ++i)
  123. pack_cell(elt(a,i));
  124. }
  125. break;
  126. default:
  127. err_printf("Unsupported vector type %x\n",type_of_header(*h));
  128. }
  129. }
  130. else if (is_symbol(a)) {
  131. Symbol_Head* h = (Symbol_Head*)( (char*)a-TAG_SYMBOL);
  132. Header My_Head = TYPE_SYMBOL;
  133. pack_32bit(My_Head);
  134. pack_atom(h->pname); /* This is a string. */
  135. }
  136. else err_printf("Unsupported type %d\n",a & TAG_BITS);
  137. }
  138. /* again, think of void pack_xxxx(void); (but actually returning int) */
  139. #define pack_space() ( check_buffer(1), \
  140. MPI_Pack(mpi_packing_symbols, 1, MPI_CHAR, \
  141. mpi_pack_buffer, mpi_pack_size, \
  142. &mpi_pack_position, MPI_COMM_WORLD) )
  143. #define pack_open() ( check_buffer(1), \
  144. MPI_Pack(mpi_packing_symbols+1, 1, MPI_CHAR, \
  145. mpi_pack_buffer, mpi_pack_size, \
  146. &mpi_pack_position, MPI_COMM_WORLD) )
  147. #define pack_close() ( check_buffer(1), \
  148. MPI_Pack(mpi_packing_symbols+2, 1, MPI_CHAR, \
  149. mpi_pack_buffer, mpi_pack_size, \
  150. &mpi_pack_position, MPI_COMM_WORLD) )
  151. #define pack_dot() ( check_buffer(1), \
  152. MPI_Pack(mpi_packing_symbols+3, 1, MPI_CHAR, \
  153. mpi_pack_buffer, mpi_pack_size, \
  154. &mpi_pack_position, MPI_COMM_WORLD) )
  155. #define pack_comma() ( check_buffer(1), \
  156. MPI_Pack(mpi_packing_symbols+4, 1, MPI_CHAR, \
  157. mpi_pack_buffer, mpi_pack_size, \
  158. &mpi_pack_position, MPI_COMM_WORLD) )
  159. static void pack_cell(Lisp_Object a)
  160. {
  161. /* In Common mode, consp needs nil defined. I don't want to
  162. * clutter the stack with unnecessary variables, so I don't
  163. * define it in CSL mode.
  164. */
  165. #ifdef COMMON
  166. Lisp_Object nil = C_nil;
  167. #endif
  168. if (consp(a)) pack_open(), pack_cell(qcar(a)), pack_list(qcdr(a));
  169. else pack_space(), pack_atom(a);
  170. }
  171. static void pack_list(Lisp_Object a)
  172. {
  173. #ifdef COMMON
  174. Lisp_Object nil = C_nil;
  175. #endif
  176. if (consp(a)) pack_comma(), pack_cell(qcar(a)), pack_list(qcdr(a));
  177. else if (a == C_nil) pack_close();
  178. else pack_dot(), pack_atom(a);
  179. }
  180. /* Now unpacking... */
  181. /* The MPI calls */
  182. /* Think of these as char unpack_char(); Lisp_Object unpack_32bit(); */
  183. #define unpack_char() (MPI_Unpack(mpi_pack_buffer, mpi_pack_size, \
  184. &mpi_pack_position, &mpi_pack_char, 1, \
  185. MPI_CHAR, MPI_COMM_WORLD), \
  186. mpi_pack_char)
  187. #define unpack_32bit() (MPI_Unpack(mpi_pack_buffer, mpi_pack_size, \
  188. &mpi_pack_position, &mpi_pack_number, 1, \
  189. MPI_UNSIGNED_LONG, MPI_COMM_WORLD), \
  190. mpi_pack_number)
  191. /* The functions to parse the linear buffer */
  192. static Lisp_Object unpack_list(void);
  193. static Lisp_Object unpack_cell(void);
  194. static Lisp_Object unpack_atom()
  195. {
  196. Lisp_Object a = unpack_32bit();
  197. if (is_fixnum(a)) return a;
  198. switch (type_of_header(a)){
  199. int size;
  200. case TYPE_DOUBLE_FLOAT:
  201. size = length_of_header(a);
  202. a = getvector(TAG_BOXFLOAT,TYPE_DOUBLE_FLOAT,size);
  203. MPI_Unpack(mpi_pack_buffer, mpi_pack_size, &mpi_pack_position,
  204. /* How ugly is this? */
  205. &(((Double_Float*)((char*)a - TAG_BOXFLOAT))->f),
  206. 1, MPI_DOUBLE, MPI_COMM_WORLD);
  207. return a;
  208. case TYPE_BIGNUM:
  209. size = length_of_header(a);
  210. a = getvector(TAG_NUMBERS,type_of_header(a),size);
  211. MPI_Unpack(mpi_pack_buffer,mpi_pack_size,&mpi_pack_position,
  212. (char*)a - TAG_NUMBERS + CELL,
  213. (size - sizeof(Header))>>2, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
  214. return a;
  215. case TYPE_STRING:
  216. size = length_of_header(a);
  217. a = getvector(TAG_VECTOR,TYPE_STRING,size);
  218. MPI_Unpack(mpi_pack_buffer, mpi_pack_size, &mpi_pack_position,
  219. (char*)a - TAG_VECTOR + CELL,
  220. size - sizeof(Header), MPI_CHAR, MPI_COMM_WORLD);
  221. return a;
  222. case TYPE_SIMPLE_VEC: case TYPE_ARRAY: case TYPE_STRUCTURE:
  223. size = length_of_header(a);
  224. push(getvector(TAG_VECTOR,type_of_header(a),size));
  225. {
  226. int i;
  227. for (i=0; i<(size>>2)-1; ++i) elt(*stack,i) = unpack_cell();
  228. if (!(i&1)) elt(*stack,i) = C_nil;
  229. }
  230. return my_pop();
  231. case TYPE_SYMBOL:
  232. {
  233. Lisp_Object nil = C_nil;
  234. a = unpack_atom(); /* Name in a string */
  235. return iintern(a, length_of_header(vechdr(a))-CELL, CP, 0);
  236. }
  237. default:
  238. err_printf("Unknown header type %d", type_of_header(a));
  239. }
  240. }
  241. static Lisp_Object unpack_cell(void)
  242. {
  243. switch (unpack_char()){
  244. case ' ': return unpack_atom();
  245. case '(': return unpack_list();
  246. default : {err_printf("Syntax error in message.\n"); return C_nil;}
  247. }
  248. }
  249. static Lisp_Object unpack_list(void)
  250. {
  251. push(unpack_cell());
  252. switch (unpack_char()){
  253. case ')': return cons(my_pop(),C_nil);
  254. case '.': {Lisp_Object tail = unpack_atom(); return cons(my_pop(), tail);}
  255. case ',': {Lisp_Object tail = unpack_list(); return cons(my_pop(), tail);}
  256. default : {err_printf("Syntax error in message.\n"); return (my_pop());}
  257. }
  258. }
  259. #endif
  260. /* end of mpipack.c */