Advertisement
djk77

master

Mar 31st, 2020
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.82 KB | None | 0 0
  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <exception>
  5. #include <iostream>
  6. #include <set>
  7. #include <stdexcept>
  8. #include <string>
  9. #include <vector>
  10.  
  11. #include <sys/stat.h>
  12. #include <sys/types.h>
  13. #include <sys/wait.h>
  14.  
  15. #include <fcntl.h>
  16. #include <unistd.h>
  17.  
  18. auto constexpr max_size = 50;
  19.  
  20. struct Pipe {
  21. std::string name;
  22. int descriptor;
  23. FILE* handle;
  24.  
  25. Pipe(std::string const& n, int fd, FILE* fh) : name{n}, descriptor{fd}, handle{fh} {}
  26. };
  27.  
  28. struct Message {
  29. enum class Type { Request, Response, Exit };
  30.  
  31. static Message read(Pipe const& pipe) {
  32. char buffer[sizeof(Message)] = { 0 };
  33. auto v = ::read(pipe.descriptor, buffer, sizeof(Message));
  34. if(v == -1 || v != sizeof(Message)) {
  35. throw std::runtime_error("Error while reading message from " + pipe.name +
  36. " read bytes: " + std::to_string(v));
  37. }
  38. Message rv;
  39. memcpy(&rv, buffer, sizeof(Message));
  40. return rv;
  41. }
  42.  
  43. static void write(Pipe& pipe, Message& message) {
  44. char buffer[sizeof(Message)] = { 0 };
  45. memcpy(buffer, &message, sizeof(Message));
  46.  
  47. auto v = ::write(pipe.descriptor, buffer, sizeof(Message));
  48. if(v == -1 || v != sizeof(Message)) {
  49. throw std::runtime_error("Error while writing message to " + pipe.name +
  50. " written bytes: " + std::to_string(v));
  51. }
  52. }
  53.  
  54. Type type;
  55. int process;
  56. int clock;
  57.  
  58. Message(Type t = Type::Request, int p = -1, int c = -1) : type{t}, process{p}, clock{c} {}
  59. };
  60.  
  61. bool operator<(Message const& lhs, Message const& rhs) {
  62. return lhs.clock < rhs.clock;
  63. }
  64.  
  65. bool operator==(Message const& lhs, Message const& rhs) {
  66. return lhs.type == rhs.type && lhs.process == rhs.process && lhs.clock == rhs.clock;
  67. }
  68.  
  69. bool operator!=(Message const& lhs, Message const& rhs) { return !(lhs == rhs); }
  70.  
  71. namespace std {
  72. std::string to_string(Message const& message) {
  73. std::string rv;
  74. switch(message.type) {
  75. case Message::Type::Request:
  76. rv += "Request";
  77. break;
  78. case Message::Type::Response:
  79. rv += "Response";
  80. break;
  81. case Message::Type::Exit:
  82. rv += "Exit";
  83. break;
  84. default:
  85. throw std::runtime_error("Unknown message type");
  86. }
  87. rv += "(" + std::to_string(message.process) + ", " + std::to_string(message.clock) + ")";
  88. return rv;
  89. }
  90. }
  91.  
  92. std::string process_prefix(int process_no) {
  93. return "Process " + std::to_string(process_no) + ": ";
  94. }
  95.  
  96. std::vector<std::string> generate_pipes(std::string const& prefix, int count) {
  97. std::clog << "Generate pipes with prefix " + prefix + " count: " + std::to_string(count) + '\n';
  98.  
  99. auto pipe_names = std::vector<std::string>(count);
  100. for(auto i = 0; i < count; ++i) {
  101. auto pipe_name = prefix + std::to_string(i);
  102. unlink(pipe_name.c_str());
  103. if(mknod(pipe_name.c_str(), S_IFIFO | 00600, 0) == -1) {
  104. throw std::runtime_error("Unable to create pipe " + pipe_name);
  105. }
  106. pipe_names[i] = pipe_name;
  107. std::clog << "Generated pipe " + pipe_name + '\n';
  108. }
  109. return pipe_names;
  110. }
  111.  
  112. std::vector<Pipe> open_pipes(std::vector<std::string> const& pipe_names, int process_no, int count) {
  113. auto pipes = std::vector<Pipe>();
  114. auto process_name = process_prefix(process_no);
  115. for(auto i = 0; i < count; ++i) {
  116. auto& pipe_name = pipe_names[i];
  117. std::clog << process_name + "opening pipe " + pipe_name + '\n';
  118. if(i == process_no) {
  119. auto fd = open(pipe_name.c_str(), O_RDONLY);
  120. if(fd == -1) {
  121. throw std::runtime_error(process_name + "unable to open " + pipe_name + " for reading");
  122. }
  123. auto fh = fdopen(fd, "r");
  124. if(fh == NULL) {
  125. throw std::runtime_error(process_name + "nable to open file " + pipe_name + " for reading");
  126. }
  127. pipes.emplace_back(pipe_name, fd, fh);
  128. std::clog << process_name + "opened pipe " + pipe_name + " for reading\n";
  129. }
  130. else {
  131. auto fd = open(pipe_name.c_str(), O_WRONLY);
  132. if(fd == -1) {
  133. throw std::runtime_error(process_name + "unable to open " + pipe_name + " for writing");
  134. }
  135. auto fh = fdopen(fd, "w");
  136. if(fh == NULL) {
  137. throw std::runtime_error(process_name + "unable to open file " + pipe_name + " for writing");
  138. }
  139. pipes.emplace_back(pipe_name, fd, fh);
  140. std::clog << process_name + "opened pipe " + pipe_name + " for writing\n";
  141. }
  142. }
  143. return pipes;
  144. }
  145.  
  146. void critical(int process_no) {
  147. auto process_name = process_prefix(process_no);
  148. for(auto i = 0; i < 5; ++i) {
  149. std::cout << process_name << " i - " << i << '\n';
  150. }
  151. }
  152.  
  153. void child(std::vector<std::string> const& pipe_names, int process_no, int count) {
  154. auto process_name = process_prefix(process_no);
  155. std::clog << process_name + "started\n";
  156.  
  157. auto pipes = open_pipes(pipe_names, process_no, count);
  158.  
  159. sleep(1);
  160.  
  161. auto time = 0;
  162. std::set<Message> queue;
  163. for(auto i = 0; i < 2; ++i) {
  164. std::clog << process_name + " wants to enter critical section\n";
  165.  
  166. //Pi requests to enter critical section
  167. auto timestamp = ++time;
  168. auto msg = Message(Message::Type::Request, process_no, timestamp);
  169. queue.insert(msg);
  170. for(auto j = 0; j < count; ++j) {
  171. if (process_no != j) {
  172. Message::write(pipes[j], msg);
  173. std::cout << process_name + "sends message [" + std::to_string(msg) + "] to " + std::to_string(j) + '\n';
  174. }
  175. }
  176. auto responses_count = 0;
  177. while((responses_count != count - 1) || *queue.begin() != msg) {
  178. std::clog << process_name + "reading from " + pipes[process_no].name + "\n";
  179. auto rec = Message::read(pipes[process_no]);
  180. std::cout << process_name + "received message [" + std::to_string(rec) + "]\n";
  181.  
  182. switch(rec.type) {
  183. case Message::Type::Request:
  184. {
  185. time = std::max(time, rec.clock) + 1;
  186. queue.insert(rec);
  187. auto response = Message(Message::Type::Response, rec.process, time);
  188. Message::write(pipes[rec.process], response);
  189. std::cout << process_name + "sends message [" + std::to_string(msg) + "] to " + std::to_string(rec.process) + '\n';
  190. break;
  191. }
  192. case Message::Type::Response:
  193. ++responses_count;
  194. break;
  195. case Message::Type::Exit:
  196. {
  197. rec.type = Message::Type::Request;
  198. queue.erase(rec);
  199. break;
  200. }
  201. }
  202.  
  203.  
  204. }
  205. critical(process_no);
  206. queue.erase(msg);
  207. msg.type = Message::Type::Exit;
  208. for(auto j = 0; j < count; ++j) {
  209. if(process_no != j) {
  210. Message::write(pipes[j], msg);
  211. std::cout << process_name + "sends message [" + std::to_string(msg) + "] to " + std::to_string(j) + '\n';
  212.  
  213. }
  214. }
  215. }
  216.  
  217. sleep(1);
  218. std::clog << process_name + "ended\n";
  219. }
  220.  
  221. int main(int argc, char** argv) {
  222. if(argc != 3) { std::cerr << "./executable pipe_name children_count"; return EXIT_FAILURE; }
  223.  
  224. auto pipe_prefix = std::string(argv[1]);
  225. auto children_count = atoi(argv[2]);
  226.  
  227. try {
  228. auto pipe_names = generate_pipes(pipe_prefix, children_count);
  229. auto parent = true;
  230. for(auto i = 0; i < children_count; ++i) {
  231. switch(fork()) {
  232. case -1:
  233. throw std::runtime_error("Unable to create child");
  234. case 0:
  235. parent = false;
  236. child(pipe_names, i, children_count);
  237. i = children_count;
  238. break;
  239. default:
  240. std::clog << "Created child " + std::to_string(i) + '\n';
  241. break;
  242.  
  243. }
  244. }
  245. //wait for children to execute
  246. if(parent) {
  247. for(auto i = 0; i < children_count; ++i) {
  248. std::clog << "Wait for child i: " << i << '\n';
  249. wait(NULL);
  250. std::clog << "Child i: " << i << " ended\n";
  251. }
  252. }
  253. }
  254. catch(std::runtime_error& e) {
  255. std::cerr << e.what() << '\n';
  256. return EXIT_FAILURE;
  257. }
  258. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement