mpipack.c 10 KB

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