Freeciv-3.1: /fast/freeciv/nightly/S3_1/ai/threaded/taiplayer.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
taiplayer.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "log.h"
20
21/* common */
22#include "ai.h"
23#include "city.h"
24#include "game.h"
25#include "unit.h"
26
27/* server/advisors */
28#include "infracache.h"
29
30/* ai/default */
31#include "aiplayer.h"
32
33/* ai/threaded */
34#include "taicity.h"
35
36#include "taiplayer.h"
37
38/* What level of operation we should abort because
39 * of received messages. Lower is more critical;
40 * TAI_ABORT_EXIT means that whole thread should exit,
41 * TAI_ABORT_NONE means that we can continue what we were doing */
42 enum tai_abort_msg_class
43{
44 TAI_ABORT_EXIT,
45 TAI_ABORT_PHASE_END,
46 TAI_ABORT_NONE
47};
48
49static enum tai_abort_msg_class tai_check_messages(struct ai_type *ait);
50
51 struct tai_thr
52{
53 int num_players;
54 struct tai_msgs msgs_to;
55 struct tai_reqs reqs_from;
56 bool thread_running;
57 fc_thread ait;
58} thrai;
59
60/**********************************************************************/
63 void tai_init_threading(void)
64{
65 thrai.thread_running = FALSE;
66
67 thrai.num_players = 0;
68}
69
70/**********************************************************************/
73 static void tai_thread_start(void *arg)
74{
75 bool finished = FALSE;
76 struct ai_type *ait = arg;
77
78 log_debug("New AI thread launched");
79
80 /* Just wait until we are signaled to shutdown */
81 fc_allocate_mutex(&thrai.msgs_to.mutex);
82 while (!finished) {
83 fc_thread_cond_wait(&thrai.msgs_to.thr_cond, &thrai.msgs_to.mutex);
84
85 if (tai_check_messages(ait) <= TAI_ABORT_EXIT) {
86 finished = TRUE;
87 }
88 }
89 fc_release_mutex(&thrai.msgs_to.mutex);
90
91 log_debug("AI thread exiting");
92}
93
94/**********************************************************************/
97 static enum tai_abort_msg_class tai_check_messages(struct ai_type *ait)
98{
99 enum tai_abort_msg_class ret_abort= TAI_ABORT_NONE;
100
101 taimsg_list_allocate_mutex(thrai.msgs_to.msglist);
102 while (taimsg_list_size(thrai.msgs_to.msglist) > 0) {
103 struct tai_msg *msg;
104 enum tai_abort_msg_class new_abort = TAI_ABORT_NONE;
105
106 msg = taimsg_list_get(thrai.msgs_to.msglist, 0);
107 taimsg_list_remove(thrai.msgs_to.msglist, msg);
108 taimsg_list_release_mutex(thrai.msgs_to.msglist);
109
110 log_debug("Plr thr got %s", taimsgtype_name(msg->type));
111
112 switch (msg->type) {
113 case TAI_MSG_FIRST_ACTIVITIES:
114 fc_allocate_mutex(&game.server.mutexes.city_list);
115
116 initialize_infrastructure_cache(msg->plr);
117
118 /* Use _safe iterate in case the main thread
119 * destroyes cities while we are iterating through these. */
120 city_list_iterate_safe(msg->plr->cities, pcity) {
121 tai_city_worker_requests_create(ait, msg->plr, pcity);
122
123 /* Release mutex for a second in case main thread
124 * wants to do something to city list. */
125 fc_release_mutex(&game.server.mutexes.city_list);
126
127 /* Recursive message check in case phase is finished. */
128 new_abort = tai_check_messages(ait);
129 fc_allocate_mutex(&game.server.mutexes.city_list);
130 if (new_abort < TAI_ABORT_NONE) {
131 break;
132 }
133 } city_list_iterate_safe_end;
134 fc_release_mutex(&game.server.mutexes.city_list);
135
136 tai_send_req(TAI_REQ_TURN_DONE, msg->plr, NULL);
137
138 break;
139 case TAI_MSG_PHASE_FINISHED:
140 new_abort = TAI_ABORT_PHASE_END;
141 break;
142 case TAI_MSG_THR_EXIT:
143 new_abort = TAI_ABORT_EXIT;
144 break;
145 default:
146 log_error("Illegal message type %s (%d) for threaded ai!",
147 taimsgtype_name(msg->type), msg->type);
148 break;
149 }
150
151 if (new_abort < ret_abort) {
152 ret_abort = new_abort;
153 }
154
155 FC_FREE(msg);
156
157 taimsg_list_allocate_mutex(thrai.msgs_to.msglist);
158 }
159 taimsg_list_release_mutex(thrai.msgs_to.msglist);
160
161 return ret_abort;
162}
163
164/**********************************************************************/
167 void tai_player_alloc(struct ai_type *ait, struct player *pplayer)
168{
169 struct tai_plr *player_data = fc_calloc(1, sizeof(struct tai_plr));
170
171 player_set_ai_data(pplayer, ait, player_data);
172
173 /* Default AI */
174 dai_data_init(ait, pplayer);
175}
176
177/**********************************************************************/
180 void tai_player_free(struct ai_type *ait, struct player *pplayer)
181{
182 struct tai_plr *player_data = player_ai_data(pplayer, ait);
183
184 /* Default AI */
185 dai_data_close(ait, pplayer);
186
187 if (player_data != NULL) {
188 player_set_ai_data(pplayer, ait, NULL);
189 FC_FREE(player_data);
190 }
191}
192
193/**********************************************************************/
196 void tai_control_gained(struct ai_type *ait, struct player *pplayer)
197{
198 thrai.num_players++;
199
200 log_debug("%s now under threaded AI (%d)", pplayer->name, thrai.num_players);
201
202 if (!thrai.thread_running) {
203 thrai.msgs_to.msglist = taimsg_list_new();
204 thrai.reqs_from.reqlist = taireq_list_new();
205
206 thrai.thread_running = TRUE;
207
208 fc_thread_cond_init(&thrai.msgs_to.thr_cond);
209 fc_init_mutex(&thrai.msgs_to.mutex);
210 fc_thread_start(&thrai.ait, tai_thread_start, ait);
211 }
212}
213
214/**********************************************************************/
217 void tai_control_lost(struct ai_type *ait, struct player *pplayer)
218{
219 thrai.num_players--;
220
221 log_debug("%s no longer under threaded AI (%d)", pplayer->name, thrai.num_players);
222
223 if (thrai.num_players <= 0) {
224 tai_send_msg(TAI_MSG_THR_EXIT, pplayer, NULL);
225
226 fc_thread_wait(&thrai.ait);
227 thrai.thread_running = FALSE;
228
229 fc_thread_cond_destroy(&thrai.msgs_to.thr_cond);
230 fc_destroy_mutex(&thrai.msgs_to.mutex);
231 taimsg_list_destroy(thrai.msgs_to.msglist);
232 taireq_list_destroy(thrai.reqs_from.reqlist);
233 }
234}
235
236/**********************************************************************/
239 void tai_refresh(struct ai_type *ait, struct player *pplayer)
240{
241 if (thrai.thread_running) {
242 taireq_list_allocate_mutex(thrai.reqs_from.reqlist);
243 while (taireq_list_size(thrai.reqs_from.reqlist) > 0) {
244 struct tai_req *req;
245
246 req = taireq_list_get(thrai.reqs_from.reqlist, 0);
247 taireq_list_remove(thrai.reqs_from.reqlist, req);
248
249 taireq_list_release_mutex(thrai.reqs_from.reqlist);
250
251 log_debug("Plr thr sent %s", taireqtype_name(req->type));
252
253 switch (req->type) {
254 case TAI_REQ_WORKER_TASK:
255 tai_req_worker_task_rcv(req);
256 break;
257 case TAI_REQ_TURN_DONE:
258 req->plr->ai_phase_done = TRUE;
259 break;
260 }
261
262 FC_FREE(req);
263
264 taireq_list_allocate_mutex(thrai.reqs_from.reqlist);
265 }
266 taireq_list_release_mutex(thrai.reqs_from.reqlist);
267 }
268}
269
270/**********************************************************************/
274 void tai_msg_to_thr(struct tai_msg *msg)
275{
276 fc_allocate_mutex(&thrai.msgs_to.mutex);
277 taimsg_list_append(thrai.msgs_to.msglist, msg);
278 fc_thread_cond_signal(&thrai.msgs_to.thr_cond);
279 fc_release_mutex(&thrai.msgs_to.mutex);
280}
281
282/**********************************************************************/
285 void tai_req_from_thr(struct tai_req *req)
286{
287 taireq_list_allocate_mutex(thrai.reqs_from.reqlist);
288 taireq_list_append(thrai.reqs_from.reqlist, req);
289 taireq_list_release_mutex(thrai.reqs_from.reqlist);
290}
291
292/**********************************************************************/
295 bool tai_thread_running(void)
296{
297 return thrai.thread_running;
298}
ai.h
dai_data_init
void dai_data_init(struct ai_type *ait, struct player *pplayer)
Definition aidata.c:59
dai_data_close
void dai_data_close(struct ai_type *ait, struct player *pplayer)
Definition aidata.c:104
aiplayer.h
city.h
city_list_iterate_safe
#define city_list_iterate_safe(citylist, _city)
Definition city.h:502
city_list_iterate_safe_end
#define city_list_iterate_safe_end
Definition city.h:524
fc_thread_cond_destroy
void fc_thread_cond_destroy(fc_thread_cond *cond)
Definition fcthread.c:385
fc_thread_cond_signal
void fc_thread_cond_signal(fc_thread_cond *cond)
Definition fcthread.c:397
fc_thread_cond_wait
void fc_thread_cond_wait(fc_thread_cond *cond, fc_mutex *mutex)
Definition fcthread.c:391
fc_thread_cond_init
void fc_thread_cond_init(fc_thread_cond *cond)
Definition fcthread.c:379
fc_thread_start
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
fc_allocate_mutex
void fc_allocate_mutex(fc_mutex *mutex)
fc_release_mutex
void fc_release_mutex(fc_mutex *mutex)
fc_thread_wait
void fc_thread_wait(fc_thread *thread)
fc_destroy_mutex
void fc_destroy_mutex(fc_mutex *mutex)
fc_init_mutex
void fc_init_mutex(fc_mutex *mutex)
game
struct civ_game game
Definition game.c:57
game.h
initialize_infrastructure_cache
void initialize_infrastructure_cache(struct player *pplayer)
Definition infracache.c:250
infracache.h
log.h
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
fc_calloc
#define fc_calloc(n, esz)
Definition mem.h:38
FC_FREE
#define FC_FREE(ptr)
Definition mem.h:41
player_ai_data
void * player_ai_data(const struct player *pplayer, const struct ai_type *ai)
Definition player.c:1904
player_set_ai_data
void player_set_ai_data(struct player *pplayer, const struct ai_type *ai, void *data)
Definition player.c:1912
ai_type
Definition ai.h:50
civ_game::server
struct civ_game::@30::@34 server
civ_game::city_list
fc_mutex city_list
Definition game.h:267
civ_game::mutexes
struct civ_game::@30::@34::@38 mutexes
player
Definition player.h:249
player::cities
struct city_list * cities
Definition player.h:281
player::name
char name[MAX_LEN_NAME]
Definition player.h:251
player::ai_phase_done
bool ai_phase_done
Definition player.h:264
tai_msg
Definition taimsg.h:33
tai_msg::plr
struct player * plr
Definition taimsg.h:35
tai_msg::type
enum taimsgtype type
Definition taimsg.h:34
tai_msgs
Definition taiplayer.h:31
tai_msgs::mutex
fc_mutex mutex
Definition taiplayer.h:33
tai_msgs::thr_cond
fc_thread_cond thr_cond
Definition taiplayer.h:32
tai_msgs::msglist
struct taimsg_list * msglist
Definition taiplayer.h:34
tai_plr
Definition taiplayer.h:43
tai_req
Definition taimsg.h:40
tai_req::plr
struct player * plr
Definition taimsg.h:42
tai_req::type
enum taireqtype type
Definition taimsg.h:41
tai_reqs
Definition taiplayer.h:38
tai_reqs::reqlist
struct taireq_list * reqlist
Definition taiplayer.h:39
tai_thr
Definition taiplayer.c:52
tai_thr::thread_running
bool thread_running
Definition taiplayer.c:56
tai_thr::num_players
int num_players
Definition taiplayer.c:53
tai_thr::msgs_to
struct tai_msgs msgs_to
Definition taiplayer.c:54
tai_thr::ait
fc_thread ait
Definition taiplayer.c:57
tai_thr::reqs_from
struct tai_reqs reqs_from
Definition taiplayer.c:55
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
tai_city_worker_requests_create
void tai_city_worker_requests_create(struct ai_type *ait, struct player *pplayer, struct city *pcity)
Definition taicity.c:65
tai_req_worker_task_rcv
void tai_req_worker_task_rcv(struct tai_req *req)
Definition taicity.c:475
taicity.h
tai_send_req
void tai_send_req(enum taireqtype type, struct player *pplayer, void *data)
Definition taimsg.c:48
tai_send_msg
void tai_send_msg(enum taimsgtype type, struct player *pplayer, void *data)
Definition taimsg.c:26
tai_msg_to_thr
void tai_msg_to_thr(struct tai_msg *msg)
Definition taiplayer.c:274
tai_thread_running
bool tai_thread_running(void)
Definition taiplayer.c:295
tai_control_gained
void tai_control_gained(struct ai_type *ait, struct player *pplayer)
Definition taiplayer.c:196
tai_control_lost
void tai_control_lost(struct ai_type *ait, struct player *pplayer)
Definition taiplayer.c:217
tai_player_alloc
void tai_player_alloc(struct ai_type *ait, struct player *pplayer)
Definition taiplayer.c:167
tai_abort_msg_class
tai_abort_msg_class
Definition taiplayer.c:43
TAI_ABORT_NONE
@ TAI_ABORT_NONE
Definition taiplayer.c:46
TAI_ABORT_PHASE_END
@ TAI_ABORT_PHASE_END
Definition taiplayer.c:45
TAI_ABORT_EXIT
@ TAI_ABORT_EXIT
Definition taiplayer.c:44
tai_player_free
void tai_player_free(struct ai_type *ait, struct player *pplayer)
Definition taiplayer.c:180
tai_init_threading
void tai_init_threading(void)
Definition taiplayer.c:63
tai_req_from_thr
void tai_req_from_thr(struct tai_req *req)
Definition taiplayer.c:285
tai_refresh
void tai_refresh(struct ai_type *ait, struct player *pplayer)
Definition taiplayer.c:239
tai_check_messages
static enum tai_abort_msg_class tai_check_messages(struct ai_type *ait)
Definition taiplayer.c:97
tai_thread_start
static void tai_thread_start(void *arg)
Definition taiplayer.c:73
thrai
struct tai_thr thrai
taiplayer.h
unit.h