1 /* 2 * Server code generation. 3 * 4 * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdlib.h> 23 #include "common.h" 24 #include "config.h" 25 #include "declaration.h" 26 #include "message.h" 27 #include "server.h" 28 #include "templates.h" 29 30 31 32 /* Generate each component operation signature or "function prototype". */ 33 34 void write_server_interface_signature(struct signature *sig, 35 enum signature_role role, FILE *fp, 36 struct interface *iface) 37 { 38 write_interface_signature(sig, role, SERVER_ROLE, fp, iface); 39 } 40 41 /* Generate signature declarations for each operation. */ 42 43 void write_server_signature(struct signature *sig, enum signature_role role, 44 FILE *fp, struct interface *iface) 45 { 46 if (have_attribute(sig->attributes, "completion")) 47 { 48 write_server_initiation_signature(sig, role, fp, iface); 49 write_server_completion_signature(sig, role, fp, iface); 50 } 51 else 52 write_server_wrapper_signature(sig, role, fp, iface); 53 } 54 55 /* Generic signature generation. */ 56 57 static void _write_server_signature(struct signature *sig, 58 enum signature_role role, 59 FILE *fp, struct interface *iface, 60 const char *prefix) 61 { 62 char *opname = get_operation_name(iface, sig); 63 64 fprintf(fp, server_function_signature, prefix, opname, iface->name); 65 fputs(get_signature_terminator(role), fp); 66 67 free(opname); 68 } 69 70 /* Generate operation wrapper function details used by the server. */ 71 72 void write_server_wrapper_signature(struct signature *sig, enum signature_role role, 73 FILE *fp, struct interface *iface) 74 { 75 _write_server_signature(sig, role, fp, iface, "wrap"); 76 } 77 78 void write_server_initiation_signature(struct signature *sig, 79 enum signature_role role, 80 FILE *fp, struct interface *iface) 81 { 82 _write_server_signature(sig, role, fp, iface, "initiate"); 83 } 84 85 void write_server_completion_signature(struct signature *sig, 86 enum signature_role role, 87 FILE *fp, struct interface *iface) 88 { 89 char *opname = get_operation_name(iface, sig); 90 91 /* Generate a signature featuring an initiator reference and only "out" and 92 "inout" parameters. */ 93 94 fprintf(fp, server_completion_function_signature_prologue, opname, iface->name); 95 96 write_parameters(sig->parameters, fp, SIGNATURE_ROLE, COMPLETION_ROLE, 97 OUT_PARAMETER, 1); 98 99 fputs(")", fp); 100 fputs(get_signature_terminator(role), fp); 101 102 free(opname); 103 } 104 105 /* Generate function source code for each operation, with the generated function 106 unpacking a message, calling the actual operation and repacking the 107 results. */ 108 109 void write_server_function(struct signature *sig, FILE *fp, struct interface *iface) 110 { 111 if (have_attribute(sig->attributes, "completion")) 112 { 113 write_server_initiation_signature(sig, DEFINITION_ROLE, fp, iface); 114 write_server_initiation_function_body(sig->parameters, fp, iface, sig); 115 fputs(END_FUNCTION, fp); 116 117 write_server_completion_signature(sig, DEFINITION_ROLE, fp, iface); 118 write_server_completion_function_body(sig->parameters, fp, iface, sig); 119 fputs(END_FUNCTION, fp); 120 } 121 else 122 { 123 write_server_wrapper_signature(sig, DEFINITION_ROLE, fp, iface); 124 write_server_wrapper_function_body(sig->parameters, fp, iface, sig); 125 fputs(END_FUNCTION, fp); 126 } 127 } 128 129 /* Generate a function body corresponding to an operation for server use. */ 130 131 void write_server_wrapper_function_body(struct parameter *param, FILE *fp, 132 struct interface *iface, struct signature *sig) 133 { 134 int input_words, input_items, output_words, output_items; 135 char *opname = get_operation_name(iface, sig); 136 137 /* Generate the prologue. */ 138 139 fputs(server_function_body_prologue, fp); 140 141 /* Count the number of input words, items and output words. */ 142 143 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 144 145 /* Generate variable declarations. */ 146 147 write_declarations(param, ANY_PARAMETER, ANY_CLASS, fp); 148 149 /* Generate types parameterised with the qualified operation name. */ 150 151 write_accessor_declaration(input_words, output_words, opname, fp); 152 153 /* Handle superfluous message structures. */ 154 155 write_superfluous_message_cast(fp, input_words, input_items, output_words, output_items); 156 157 /* Unpack each word and item from the message into variables. */ 158 159 write_input_initialisation(param, fp, opname, input_words, input_items); 160 161 /* Invoke the actual operation using the variables. */ 162 163 write_server_function_call(param, fp, iface, sig, ANY_PARAMETER); 164 165 /* Pack the outputs into the message and perform any other housekeeping. */ 166 167 write_output_initialisation(param, fp, opname, output_words, output_items, GENERAL_FUNCTION_ROLE); 168 169 /* Return the success of the reply operation. */ 170 171 fputs(server_function_body_epilogue, fp); 172 173 /* Free allocated strings. */ 174 175 free(opname); 176 } 177 178 /* Generate a function body corresponding to the initiation of an operation. */ 179 180 void write_server_initiation_function_body(struct parameter *param, FILE *fp, 181 struct interface *iface, 182 struct signature *sig) 183 { 184 int input_words, input_items, output_words, output_items; 185 char *opname = get_operation_name(iface, sig); 186 187 /* Generate the prologue. */ 188 189 fputs(server_function_body_prologue, fp); 190 191 /* Count the number of input words, items and output words. */ 192 193 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 194 195 /* Generate variable declarations for "in" and "inout" parameters. */ 196 197 write_declarations(param, IN_PARAMETER, ANY_CLASS, fp); 198 199 /* Generate types parameterised with the qualified operation name. */ 200 201 write_accessor_declaration(input_words, 0, opname, fp); 202 203 /* Handle superfluous message structures. */ 204 205 write_superfluous_message_cast(fp, input_words, input_items, 0, 0); 206 207 /* Unpack each word and item from the message into variables. */ 208 209 write_input_initialisation(param, fp, opname, input_words, input_items); 210 211 /* Invoke the actual operation using the variables. */ 212 213 write_server_function_call(param, fp, iface, sig, IN_PARAMETER); 214 215 /* Return the success of the operation restoring buffer registers. */ 216 217 fputs(server_initiation_function_body_epilogue, fp); 218 219 /* Free allocated strings. */ 220 221 free(opname); 222 } 223 224 /* Generate a function body corresponding to the completion of an operation. */ 225 226 void write_server_completion_function_body(struct parameter *param, FILE *fp, 227 struct interface *iface, 228 struct signature *sig) 229 { 230 int input_words, input_items, output_words, output_items; 231 char *opname = get_operation_name(iface, sig); 232 233 /* Generate the prologue. */ 234 235 fputs(server_completion_function_body_prologue, fp); 236 237 /* Count the number of input words, items and output words. */ 238 239 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 240 241 /* Generate types parameterised with the qualified operation name. */ 242 243 write_accessor_declaration(0, output_words, opname, fp); 244 245 /* Initialise the message. */ 246 247 fprintf(fp, "\n ipc_message_new(&msg);\n"); 248 249 /* Pack the outputs into the message and perform any other housekeeping. */ 250 251 write_output_initialisation(param, fp, opname, output_words, output_items, COMPLETION_ROLE); 252 253 /* Send the response. 254 NOTE: The label 0 is employed but an error condition could be communicated. */ 255 256 fprintf(fp, server_completion_function_body_epilogue, "0", "_endp"); 257 258 /* Free allocated strings. */ 259 260 free(opname); 261 } 262 263 /* Generate a cast for superfluous message structures. */ 264 265 void write_superfluous_message_cast(FILE *fp, int input_words, int input_items, 266 int output_words, int output_items) 267 { 268 if (!input_words && !input_items && !output_words && !output_items) 269 fputs(server_function_body_unused_message, fp); 270 } 271 272 /* Generate the initialisation of input words and items. */ 273 274 void write_input_initialisation(struct parameter *param, FILE *fp, 275 const char *opname, int input_words, 276 int input_items) 277 { 278 if (input_words) 279 { 280 write_accessor_initialisation(IN_PARAMETER, SERVER_ROLE, GENERAL_FUNCTION_ROLE, 281 opname, fp); 282 write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 283 WORD_CLASS, fp); 284 } 285 286 if (input_items) 287 { 288 fputs("\n", fp); 289 write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 290 ITEM_CLASS, fp); 291 } 292 } 293 294 /* Generate the initialisation of output words and items. */ 295 296 void write_output_initialisation(struct parameter *param, FILE *fp, 297 const char *opname, int output_words, 298 int output_items, enum function_role function) 299 { 300 if (output_words) 301 { 302 write_accessor_initialisation(OUT_PARAMETER, SERVER_ROLE, function, 303 opname, fp); 304 write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER, 305 WORD_CLASS, fp); 306 } 307 308 if (output_items) 309 { 310 fputs("\n", fp); 311 write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER, 312 ITEM_CLASS, fp); 313 } 314 } 315 316 /* Generate an invocation of the actual server operation. */ 317 318 void write_server_function_call(struct parameter *param, FILE *fp, 319 struct interface *iface, struct signature *sig, 320 enum specifier specifier) 321 { 322 int continuing = 0; 323 char *name, *addr, 324 *opname = get_signature_operation_name(iface, sig, SERVER_ROLE, 325 ACCESS_ROLE, conf.language); 326 327 fputs("\n err = ", fp); 328 329 /* Access a method when emitting C++. */ 330 331 if (conf.language == CPP_LANGUAGE) 332 fprintf(fp, "_self->%s(", opname); 333 334 /* Employ a function pointer via the object type otherwise. */ 335 336 else 337 { 338 fprintf(fp, "_self->iface->%s(_self->ref", opname); 339 continuing = 1; 340 } 341 342 /* Generate the parameter list, employing addresses for output parameters. */ 343 344 write_parameters(param, fp, INVOCATION_ROLE, GENERAL_FUNCTION_ROLE, specifier, 345 continuing); 346 fputs(");\n", fp); 347 348 /* Emit post-invocation details. */ 349 350 fputs(server_function_body_call, fp); 351 352 /* Free allocated strings. */ 353 354 free(opname); 355 }