[boinc] 01/12: Imported Upstream version 7.4.14+dfsg
Gianfranco Costamagna
locutusofborg-guest at moszumanska.debian.org
Wed Aug 13 20:30:43 UTC 2014
This is an automated email from the git hooks/post-receive script.
locutusofborg-guest pushed a commit to branch master
in repository boinc.
commit efad3c040ba9e9d871672efdefc5cf8af6acdf1d
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Tue Aug 12 11:06:09 2014 +0200
Imported Upstream version 7.4.14+dfsg
---
android/BOINC/AndroidManifest.xml | 4 +-
.../attach_project_batch_processing_layout.xml | 14 ++
.../layout/attach_project_list_layout_listitem.xml | 10 ++
android/BOINC/res/menu/projects_menu.xml | 4 -
android/BOINC/res/values/strings.xml | 10 +-
.../src/edu/berkeley/boinc/ProjectsFragment.java | 18 --
.../edu/berkeley/boinc/attach/AcctMgrFragment.java | 20 ++-
.../boinc/attach/BatchProcessingActivity.java | 15 +-
.../boinc/attach/SelectionListActivity.java | 10 ++
.../boinc/attach/SelectionListAdapter.java | 63 +++++--
client/app.cpp | 22 ++-
client/app.h | 10 +-
client/app_config.cpp | 34 +++-
client/app_config.h | 2 +
client/app_control.cpp | 91 +++++-----
client/app_start.cpp | 64 ++++---
client/client_state.cpp | 30 +++-
client/client_state.h | 9 +-
client/client_types.cpp | 12 +-
client/client_types.h | 4 +-
client/cpu_sched.cpp | 19 +-
client/cs_account.cpp | 4 +-
client/cs_cmdline.cpp | 4 -
client/cs_notice.cpp | 3 +
client/cs_scheduler.cpp | 36 ++--
client/cs_trickle.cpp | 14 +-
client/file_names.h | 1 +
client/gpu_detect.cpp | 76 ++++++++
client/gpu_detect.h | 9 +
client/gpu_opencl.cpp | 75 ++++++--
client/project.cpp | 6 +
client/project.h | 5 +
client/result.h | 17 +-
client/rr_sim.cpp | 48 +++---
client/sandbox.cpp | 192 ++++++++++++++++-----
client/scheduler_op.cpp | 2 +
client/sim.cpp | 21 +--
client/switcher.cpp | 10 +-
client/work_fetch.cpp | 49 +++++-
client/work_fetch.h | 2 +
clientgui/DlgAdvPreferences.cpp | 28 ++-
clientgui/DlgAdvPreferencesBase.cpp | 121 +++++++------
clientgui/DlgAdvPreferencesBase.h | 3 +-
clientgui/MainDocument.cpp | 34 ++++
clientgui/MainDocument.h | 1 +
clientgui/ViewResources.cpp | 30 +---
clientgui/ViewStatistics.cpp | 38 +---
clientgui/ViewStatistics.h | 12 --
configure.ac | 2 +-
db/boinc_db_types.h | 5 +
lib/coproc.cpp | 44 +++--
lib/coproc.h | 41 ++++-
lib/error_numbers.h | 1 +
lib/gui_rpc_client.h | 1 +
lib/gui_rpc_client_ops.cpp | 2 +
lib/gui_rpc_client_print.cpp | 1 +
lib/opencl_boinc.h | 4 +-
lib/proc_control.cpp | 4 +
lib/procinfo_mac.cpp | 7 +-
lib/shmem.cpp | 2 +-
lib/str_util.cpp | 1 +
lib/util.cpp | 25 +++
lib/util.h | 2 +
sched/handle_request.cpp | 7 +-
sched/sched_types.cpp | 11 +-
65 files changed, 1030 insertions(+), 436 deletions(-)
diff --git a/android/BOINC/AndroidManifest.xml b/android/BOINC/AndroidManifest.xml
index 1b230a0..1eba712 100644
--- a/android/BOINC/AndroidManifest.xml
+++ b/android/BOINC/AndroidManifest.xml
@@ -20,8 +20,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="edu.berkeley.boinc"
android:installLocation="internalOnly"
- android:versionCode="83"
- android:versionName="7.4.8" > <!-- installation on SD card would break boot receiver -->
+ android:versionCode="89"
+ android:versionName="7.4.14" > <!-- installation on SD card would break boot receiver -->
<!-- Add Google Play store metadata informing the store we can run on tablets and other large screen devices -->
diff --git a/android/BOINC/res/layout/attach_project_batch_processing_layout.xml b/android/BOINC/res/layout/attach_project_batch_processing_layout.xml
index 61e1584..c950bcb 100644
--- a/android/BOINC/res/layout/attach_project_batch_processing_layout.xml
+++ b/android/BOINC/res/layout/attach_project_batch_processing_layout.xml
@@ -113,6 +113,20 @@
</LinearLayout>
<Button
+ android:id="@+id/share_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/social_invite_button"
+ android:textColor="@android:color/white"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:background="@drawable/shape_button_blue"
+ android:minWidth="150dp"
+ android:padding="5dp"
+ android:layout_margin="10dp"
+ android:onClick="shareClicked"
+ android:visibility="gone"/>
+
+ <Button
android:id="@+id/continue_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/android/BOINC/res/layout/attach_project_list_layout_listitem.xml b/android/BOINC/res/layout/attach_project_list_layout_listitem.xml
index 081df81..2d5ba7f 100644
--- a/android/BOINC/res/layout/attach_project_list_layout_listitem.xml
+++ b/android/BOINC/res/layout/attach_project_list_layout_listitem.xml
@@ -51,5 +51,15 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>
+
+ <ImageView
+ android:id="@+id/am_button_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/nextb"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:visibility="gone"
+ android:contentDescription="@string/attachproject_acctmgr_header"/>
</RelativeLayout>
diff --git a/android/BOINC/res/menu/projects_menu.xml b/android/BOINC/res/menu/projects_menu.xml
index 80eaaef..3b78310 100644
--- a/android/BOINC/res/menu/projects_menu.xml
+++ b/android/BOINC/res/menu/projects_menu.xml
@@ -25,10 +25,6 @@
android:title="@string/projects_add"
android:icon="@drawable/plusw"
yourapp:showAsAction="ifRoom|withText"></item>
- <item android:id="@+id/acctmgr_add"
- android:enabled="true"
- android:visible="true"
- android:title="@string/attachproject_list_acctmgr_button"></item>
<item android:id="@+id/projects_add_url"
android:enabled="true"
android:visible="true"
diff --git a/android/BOINC/res/values/strings.xml b/android/BOINC/res/values/strings.xml
index f0fa05f..59d70b3 100644
--- a/android/BOINC/res/values/strings.xml
+++ b/android/BOINC/res/values/strings.xml
@@ -29,7 +29,7 @@
<!-- attach project -->
<!-- selection list -->
- <string name="attachproject_list_desc">Select scientific projects you want to contribute in:</string>
+ <string name="attachproject_list_desc">Select scientific projects you want to contribute to:</string>
<string name="attachproject_list_header">Choose a project</string>
<string name="attachproject_list_manual_button">Add project by URL</string>
<string name="attachproject_list_manual_dialog_title">Enter project URL:</string>
@@ -98,6 +98,7 @@
<string name="attachproject_registration_header_pwd_confirm">… Retype:</string>
<string name="attachproject_registration_button">Create</string>
<!-- account manager -->
+ <string name="attachproject_acctmgr_list_desc">Use BOINC account manager to add and manage multiple projects</string>
<string name="attachproject_acctmgr_header">Add account manager</string>
<string name="attachproject_acctmgr_header_url">URL</string>
<string name="attachproject_acctmgr_header_name">User:</string>
@@ -382,5 +383,12 @@
<string name="nonexcl_dialog_header">Volunteer computing app detected</string>
<string name="nonexcl_dialog_text">Another volunteer computing app is running on this device. Only one version can run at a time.</string>
<string name="nonexcl_dialog_exit">Exit</string>
+
+ <!-- social integration -->
+ <string name="social_invite_button">Invite friends</string>
+ <string name="social_invite_intent_title">How do you want to share?</string>
+ <string name="social_invite_content_title">I\'m doing science on my smartphone!</string>
+ <string name="social_invite_content_body">I\'m using my %1$s to do computing for science. You can too! Download the app from: %2$s</string> <!-- first parameter: device manufacturer, second: URL -->
+ <string name="social_invite_content_url">https://play.google.com/store/apps/details?id=edu.berkeley.boinc</string>
</resources>
diff --git a/android/BOINC/src/edu/berkeley/boinc/ProjectsFragment.java b/android/BOINC/src/edu/berkeley/boinc/ProjectsFragment.java
index 5c4d881..10a225b 100644
--- a/android/BOINC/src/edu/berkeley/boinc/ProjectsFragment.java
+++ b/android/BOINC/src/edu/berkeley/boinc/ProjectsFragment.java
@@ -45,7 +45,6 @@ import android.widget.ListView;
import android.widget.TextView;
import edu.berkeley.boinc.adapter.ProjectControlsListAdapter;
import edu.berkeley.boinc.adapter.ProjectsListAdapter;
-import edu.berkeley.boinc.attach.AcctMgrFragment;
import edu.berkeley.boinc.attach.ManualUrlInputFragment;
import edu.berkeley.boinc.rpc.Notice;
import edu.berkeley.boinc.rpc.AcctMgrInfo;
@@ -58,7 +57,6 @@ public class ProjectsFragment extends Fragment {
private ListView lv;
private ProjectsListAdapter listAdapter;
private ArrayList<ProjectsListData> data = new ArrayList<ProjectsListData>();
- private Boolean acctMgrPresent = false;
// controls popup dialog
Dialog dialogControls;
@@ -117,25 +115,10 @@ public class ProjectsFragment extends Fragment {
}
@Override
- public void onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
-
- // disable "add account manager" button, if account manager already present
- if(acctMgrPresent) {
- MenuItem item = menu.findItem(R.id.acctmgr_add);
- item.setVisible(false);
- }
- }
-
- @Override
public boolean onOptionsItemSelected(MenuItem item) {
if(Logging.VERBOSE) Log.v(Logging.TAG, "AttachProjectListActivity onOptionsItemSelected()");
switch (item.getItemId()) {
- case R.id.acctmgr_add:
- AcctMgrFragment dialog = new AcctMgrFragment();
- dialog.show(getFragmentManager(), getActivity().getString(R.string.attachproject_acctmgr_header));
- return true;
case R.id.projects_add_url:
ManualUrlInputFragment dialog2 = new ManualUrlInputFragment();
dialog2.show(getFragmentManager(), getActivity().getString(R.string.attachproject_list_manual_button));
@@ -149,7 +132,6 @@ public class ProjectsFragment extends Fragment {
try {
// read projects from state saved in ClientStatus
ArrayList<Project> statusProjects = (ArrayList<Project>) BOINCActivity.monitor.getProjects();
- acctMgrPresent = BOINCActivity.monitor.getAcctMgrInfoPresent();
AcctMgrInfo statusAcctMgr = BOINCActivity.monitor.getClientAcctMgrInfo();
ArrayList<Transfer> statusTransfers = (ArrayList<Transfer>) BOINCActivity.monitor.getTransfers();
diff --git a/android/BOINC/src/edu/berkeley/boinc/attach/AcctMgrFragment.java b/android/BOINC/src/edu/berkeley/boinc/attach/AcctMgrFragment.java
index 3526383..634c599 100644
--- a/android/BOINC/src/edu/berkeley/boinc/attach/AcctMgrFragment.java
+++ b/android/BOINC/src/edu/berkeley/boinc/attach/AcctMgrFragment.java
@@ -19,6 +19,7 @@
package edu.berkeley.boinc.attach;
+import edu.berkeley.boinc.BOINCActivity;
import edu.berkeley.boinc.R;
import edu.berkeley.boinc.utils.*;
import android.app.Dialog;
@@ -59,6 +60,8 @@ public class AcctMgrFragment extends DialogFragment{
private LinearLayout ongoingWrapper;
private Button continueB;
+ private boolean returnToMainActivity = false;
+
private AttachProjectAsyncTask asyncTask;
@Override
@@ -132,6 +135,10 @@ public class AcctMgrFragment extends DialogFragment{
return dialog;
}
+ public void setReturnToMainActivity() {
+ returnToMainActivity = true;
+ }
+
private int verifyInput(String url, String name, String pwd) {
int stringResource = 0;
@@ -254,7 +261,18 @@ public class AcctMgrFragment extends DialogFragment{
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment.AttachProjectAsyncTask onPostExecute, returned: " + result);
- if(result == BOINCErrors.ERR_OK) dismiss();
+ if(result == BOINCErrors.ERR_OK) {
+ dismiss();
+ if(returnToMainActivity) {
+ if(Logging.DEBUG) Log.d(Logging.TAG, "AcctMgrFragment.AttachProjectAsyncTask onPostExecute, start main activity");
+ Intent intent = new Intent(getActivity(), BOINCActivity.class);
+ // add flags to return to main activity and clearing all others and clear the back stack
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra("targetFragment", R.string.tab_projects); // make activity display projects fragment
+ startActivity(intent);
+ }
+ }
else {
ongoingWrapper.setVisibility(View.GONE);
continueB.setVisibility(View.VISIBLE);
diff --git a/android/BOINC/src/edu/berkeley/boinc/attach/BatchProcessingActivity.java b/android/BOINC/src/edu/berkeley/boinc/attach/BatchProcessingActivity.java
index 44bce50..11231e2 100644
--- a/android/BOINC/src/edu/berkeley/boinc/attach/BatchProcessingActivity.java
+++ b/android/BOINC/src/edu/berkeley/boinc/attach/BatchProcessingActivity.java
@@ -116,7 +116,6 @@ public class BatchProcessingActivity extends FragmentActivity{
}
// triggered by continue button
- // button only visible if no conflicts occured.
public void continueClicked(View v) {
boolean conflicts = attachService.unresolvedConflicts();
if(Logging.DEBUG) Log.d(Logging.TAG, "BatchProcessingActivity.continueClicked: conflicts? " + conflicts);
@@ -137,6 +136,19 @@ public class BatchProcessingActivity extends FragmentActivity{
startActivity(intent);
}
}
+
+ // triggered by share button
+ public void shareClicked(View v) {
+ if(Logging.DEBUG) Log.d(Logging.TAG, "BatchProcessingActivity.shareClicked.");
+ Intent intent=new Intent(android.content.Intent.ACTION_SEND);
+ intent.setType("text/plain");
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+
+ // Add data to the intent, the receiving app will decide what to do with it.
+ intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.social_invite_content_title));
+ intent.putExtra(Intent.EXTRA_TEXT, String.format(getString(R.string.social_invite_content_body), android.os.Build.MANUFACTURER, getString(R.string.social_invite_content_url)));
+ startActivity(Intent.createChooser(intent, getString(R.string.social_invite_intent_title)));
+ }
// adapts header text and icons when hint selection changes
private void adaptHintHeader() {
@@ -240,6 +252,7 @@ public class BatchProcessingActivity extends FragmentActivity{
protected void onPostExecute(Void result) {
((LinearLayout) findViewById(R.id.attach_status_ongoing_wrapper)).setVisibility(View.GONE);
((Button) findViewById(R.id.continue_button)).setVisibility(View.VISIBLE);
+ ((Button) findViewById(R.id.share_button)).setVisibility(View.VISIBLE);
super.onPostExecute(result);
}
}
diff --git a/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListActivity.java b/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListActivity.java
index 523a4f0..b47fb59 100644
--- a/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListActivity.java
+++ b/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListActivity.java
@@ -203,6 +203,8 @@ public class SelectionListActivity extends FragmentActivity{
for(ProjectInfo tmp: result) {
entries.add(new ProjectListEntry(tmp));
}
+
+ entries.add(new ProjectListEntry()); // add account manager option to bottom of list
SelectionListAdapter listAdapter = new SelectionListAdapter(SelectionListActivity.this,R.id.listview,entries);
lv.setAdapter(listAdapter);
}
@@ -212,10 +214,18 @@ public class SelectionListActivity extends FragmentActivity{
class ProjectListEntry {
public ProjectInfo info;
public boolean checked;
+ public boolean am; //indicates that element is account manager entry
public ProjectListEntry(ProjectInfo info) {
this.info = info;
this.checked = false;
}
+
+ /**
+ * Creates Account manager list object
+ */
+ public ProjectListEntry() {
+ this.am = true;
+ }
}
}
diff --git a/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListAdapter.java b/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListAdapter.java
index d0254a3..9fac9db 100644
--- a/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListAdapter.java
+++ b/android/BOINC/src/edu/berkeley/boinc/attach/SelectionListAdapter.java
@@ -31,6 +31,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -56,29 +57,55 @@ public class SelectionListAdapter extends ArrayAdapter<ProjectListEntry>{
v = vi.inflate(R.layout.attach_project_list_layout_listitem, null);
TextView name = (TextView) v.findViewById(R.id.name);
- name.setText(listItem.info.name);
TextView description = (TextView) v.findViewById(R.id.description);
- description.setText(listItem.info.generalArea);
TextView summary = (TextView) v.findViewById(R.id.summary);
- summary.setText(listItem.info.summary);
CheckBox cb = (CheckBox) v.findViewById(R.id.cb);
- cb.setChecked(listItem.checked);
- cb.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- listItem.checked = !listItem.checked;
- }
- });
LinearLayout textWrapper = (LinearLayout) v.findViewById(R.id.text_wrapper);
- textWrapper.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if(Logging.DEBUG) Log.d(Logging.TAG, "SelectionListAdapter: onProjectClick open info for: " + listItem.info.name);
+
+ if(listItem.am) {
+ // element is account manager
+ name.setText(activity.getString(R.string.attachproject_acctmgr_header));
+ description.setText(activity.getString(R.string.attachproject_acctmgr_list_desc));
+ cb.setVisibility(View.GONE);
+ summary.setVisibility(View.GONE);
+ ImageView button = (ImageView) v.findViewById(R.id.am_button_image);
+ button.setVisibility(View.VISIBLE);
+ OnClickListener listener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(Logging.DEBUG) Log.d(Logging.TAG, "SelectionListAdapter: account manager clicked.");
+ AcctMgrFragment dialog = new AcctMgrFragment();
+ dialog.setReturnToMainActivity(); // configure, so dialog returns to main activity when finished
+ dialog.show(activity.getSupportFragmentManager(), activity.getString(R.string.attachproject_acctmgr_header));
+ }
+ };
+ v.setOnClickListener(listener);
+ name.setOnClickListener(listener);
+ description.setOnClickListener(listener);
+ button.setOnClickListener(listener);
+ } else {
+ // element is project option
+ name.setText(listItem.info.name);
+ description.setText(listItem.info.generalArea);
+ summary.setText(listItem.info.summary);
+ cb.setChecked(listItem.checked);
+ cb.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ listItem.checked = !listItem.checked;
+ }
+ });
+ textWrapper.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(Logging.DEBUG) Log.d(Logging.TAG, "SelectionListAdapter: onProjectClick open info for: " + listItem.info.name);
- ProjectInfoFragment dialog = ProjectInfoFragment.newInstance(listItem.info);
- dialog.show(activity.getSupportFragmentManager(), "ProjectInfoFragment");
- }
- });
+ ProjectInfoFragment dialog = ProjectInfoFragment.newInstance(listItem.info);
+ dialog.show(activity.getSupportFragmentManager(), "ProjectInfoFragment");
+ }
+ });
+
+ }
return v;
}
diff --git a/client/app.cpp b/client/app.cpp
index 1e6ab4c..3c85200 100644
--- a/client/app.cpp
+++ b/client/app.cpp
@@ -140,6 +140,17 @@ ACTIVE_TASK::ACTIVE_TASK() {
finish_file_time = 0;
}
+bool ACTIVE_TASK::process_exists() {
+ switch (task_state()) {
+ case PROCESS_EXECUTING:
+ case PROCESS_SUSPENDED:
+ case PROCESS_ABORT_PENDING:
+ case PROCESS_QUIT_PENDING:
+ return true;
+ }
+ return false;
+}
+
// preempt this task;
// called from the CLIENT_STATE::enforce_schedule()
// and ACTIVE_TASK_SET::suspend_all()
@@ -198,7 +209,9 @@ int ACTIVE_TASK::preempt(int preempt_type, int reason) {
#ifndef SIM
-// called when a process has exited
+// called when the task's main process has exited.
+// delete the shared memory used to communicate with it,
+// and kill any remaining subsidiary processes.
//
void ACTIVE_TASK::cleanup_task() {
#ifdef _WIN32
@@ -218,7 +231,7 @@ void ACTIVE_TASK::cleanup_task() {
if (app_client_shm.shm) {
#ifndef __EMX__
- if (app_version->api_major_version() >= 6) {
+ if (app_version->api_version_at_least(6, 0)) {
retval = detach_shmem_mmap(app_client_shm.shm, sizeof(SHARED_MEM));
} else
#endif
@@ -241,6 +254,8 @@ void ACTIVE_TASK::cleanup_task() {
}
#endif
+ kill_subsidiary_processes();
+
if (cc_config.exit_after_finish) {
gstate.write_state_file();
exit(0);
@@ -343,7 +358,8 @@ void ACTIVE_TASK_SET::get_memory_usage() {
}
PROCINFO boinc_total;
if (log_flags.mem_usage_debug) {
- memset(&boinc_total, 0, sizeof(boinc_total));
+ boinc_total.clear();
+ boinc_total.working_set_size_smoothed = 0;
}
for (i=0; i<active_tasks.size(); i++) {
ACTIVE_TASK* atp = active_tasks[i];
diff --git a/client/app.h b/client/app.h
index 03263bf..5c73500 100644
--- a/client/app.h
+++ b/client/app.h
@@ -207,7 +207,6 @@ struct ACTIVE_TASK {
// Termination stuff.
// Terminology:
// "kill": forcibly kill the main process and all its descendants.
- // (note: on Windows secure mode, we can't kill the descendants)
// "request exit": send a request-exit message, and enumerate descendants.
// If after 15 secs any processes remain, kill them
// called from:
@@ -226,9 +225,12 @@ struct ACTIVE_TASK {
//
int request_exit();
int request_abort();
- int kill_task(bool will_restart);
- // Kill process and descendants forcibly.
+ int kill_running_task(bool will_restart);
+ // Kill process and subsidiary processes forcibly.
// Unix: send a SIGKILL signal, Windows: TerminateProcess()
+ int kill_subsidiary_processes();
+ // kill subsidiary processes of a job
+ // whose main process has already exited
int abort_task(int exit_status, const char*);
// can be called whether or not process exists
@@ -242,6 +244,8 @@ struct ACTIVE_TASK {
// Implementation stuff related to termination
//
std::vector<int> descendants;
+ // PIDs of descendants, computed every 10 sec or so
+ // during resource usage computation.
bool process_exists();
bool has_task_exited();
// return true if this task has exited
diff --git a/client/app_config.cpp b/client/app_config.cpp
index e65bee0..5e01e7e 100644
--- a/client/app_config.cpp
+++ b/client/app_config.cpp
@@ -29,6 +29,7 @@ bool have_max_concurrent = false;
int APP_CONFIG::parse(XML_PARSER& xp, PROJECT* p) {
memset(this, 0, sizeof(APP_CONFIG));
+ double x;
while (!xp.get_tag()) {
if (xp.match_tag("/app")) return 0;
@@ -40,8 +41,26 @@ int APP_CONFIG::parse(XML_PARSER& xp, PROJECT* p) {
if (xp.match_tag("gpu_versions")) {
while (!xp.get_tag()) {
if (xp.match_tag("/gpu_versions")) break;
- if (xp.parse_double("gpu_usage", gpu_gpu_usage)) continue;
- if (xp.parse_double("cpu_usage", gpu_cpu_usage)) continue;
+ if (xp.parse_double("gpu_usage", x)) {
+ if (x <= 0) {
+ msg_printf(p, MSG_USER_ALERT,
+ "gpu_usage must be positive in app_config.xml"
+ );
+ } else {
+ gpu_gpu_usage = x;
+ }
+ continue;
+ }
+ if (xp.parse_double("cpu_usage", x)) {
+ if (x < 0) {
+ msg_printf(p, MSG_USER_ALERT,
+ "cpu_usage must be non-negative in app_config.xml"
+ );
+ } else {
+ gpu_cpu_usage = x;
+ }
+ continue;
+ }
}
continue;
}
@@ -81,6 +100,7 @@ int APP_VERSION_CONFIG::parse(XML_PARSER& xp, PROJECT* p) {
}
int APP_CONFIGS::parse(XML_PARSER& xp, PROJECT* p) {
+ int n;
app_configs.clear();
if (!xp.parse_start("app_config")) return ERR_XML_PARSE;
while (!xp.get_tag()) {
@@ -101,6 +121,13 @@ int APP_CONFIGS::parse(XML_PARSER& xp, PROJECT* p) {
}
continue;
}
+ if (xp.parse_int("project_max_concurrent", n)) {
+ if (n >= 0) {
+ have_max_concurrent = true;
+ project_max_concurrent = n;
+ }
+ continue;
+ }
if (log_flags.unparsed_xml) {
msg_printf(p, MSG_INFO,
"Unparsed line in app_config.xml: %s",
@@ -183,6 +210,9 @@ void max_concurrent_init() {
for (unsigned int i=0; i<gstate.apps.size(); i++) {
gstate.apps[i]->n_concurrent = 0;
}
+ for (unsigned int i=0; i<gstate.projects.size(); i++) {
+ gstate.projects[i]->n_concurrent = 0;
+ }
}
// undo the effects of an app_config.xml that no longer exists
diff --git a/client/app_config.h b/client/app_config.h
index 81c6c11..3d54570 100644
--- a/client/app_config.h
+++ b/client/app_config.h
@@ -50,6 +50,7 @@ struct APP_VERSION_CONFIG {
struct APP_CONFIGS {
std::vector<APP_CONFIG> app_configs;
std::vector<APP_VERSION_CONFIG> app_version_configs;
+ int project_max_concurrent;
int parse(XML_PARSER&, PROJECT*);
int parse_file(FILE*, PROJECT*);
@@ -57,6 +58,7 @@ struct APP_CONFIGS {
void clear() {
app_configs.clear();
app_version_configs.clear();
+ project_max_concurrent = 0;
}
};
diff --git a/client/app_control.cpp b/client/app_control.cpp
index a8f6010..ee64e5a 100644
--- a/client/app_control.cpp
+++ b/client/app_control.cpp
@@ -105,7 +105,7 @@ bool ACTIVE_TASK_SET::poll() {
atp->result->name
);
}
- atp->kill_task(false);
+ atp->kill_running_task(false);
}
}
if (atp->task_state() == PROCESS_QUIT_PENDING) {
@@ -116,7 +116,7 @@ bool ACTIVE_TASK_SET::poll() {
atp->result->name
);
}
- atp->kill_task(true);
+ atp->kill_running_task(true);
}
}
}
@@ -211,29 +211,34 @@ int ACTIVE_TASK::request_abort() {
#ifdef _WIN32
static void kill_app_process(int pid, bool will_restart) {
- HANDLE h = OpenProcess(READ_CONTROL | PROCESS_TERMINATE, false, pid);
- if (h == NULL) return;
- TerminateProcess(h, will_restart?0:EXIT_ABORTED_BY_CLIENT);
- CloseHandle(h);
-}
-#else
-static void kill_app_process(int pid, bool) {
int retval = 0;
-#ifdef SANDBOX
- retval = kill_via_switcher(pid);
+ retval = kill_program(pid, will_restart?0:EXIT_ABORTED_BY_CLIENT);
if (retval && log_flags.task_debug) {
msg_printf(0, MSG_INFO,
- "[task] kill_via_switcher() failed: %s",
- boincerror(retval)
+ "[task] kill_app_process() failed: %s",
+ strerror(retval)
);
}
-#endif
- retval = kill(pid, SIGKILL);
- if (retval && log_flags.task_debug) {
- msg_printf(0, MSG_INFO,
- "[task] kill() failed: %s",
- boincerror(retval)
- );
+}
+#else
+static void kill_app_process(int pid, bool) {
+ int retval = 0;
+ if (g_use_sandbox) {
+ retval = kill_via_switcher(pid);
+ if (retval && log_flags.task_debug) {
+ msg_printf(0, MSG_INFO,
+ "[task] kill_via_switcher() failed: %s (%d)",
+ (retval>=0) ? strerror(errno) : boincerror(retval), retval
+ );
+ }
+ } else {
+ retval = kill(pid, SIGKILL);
+ if (retval && log_flags.task_debug) {
+ msg_printf(0, MSG_INFO,
+ "[task] kill() failed: %s",
+ strerror(errno)
+ );
+ }
}
}
#endif
@@ -244,27 +249,24 @@ static inline void kill_processes(vector<int> pids, bool will_restart) {
}
}
-// Kill the task (and descendants) by OS-specific means.
+// Kill a task whose main process is still running
+// Just kill the main process; shared mem and subsidiary processes
+// will be cleaned up after it exits, by cleanup_task();
//
-int ACTIVE_TASK::kill_task(bool will_restart) {
- vector<int>pids;
-#ifdef _WIN32
- // On Win, in protected mode we won't be able to get
- // handles for the descendant processes;
- // all we can do is terminate the main process,
- // using the handle we got when we created it.
- //
- if (g_use_sandbox) {
- TerminateProcess(process_handle, will_restart?0:EXIT_ABORTED_BY_CLIENT);
- return 0;
- }
-#endif
- get_descendants(pid, pids);
- pids.push_back(pid);
- for (unsigned int i=0; i<other_pids.size(); i++) {
- pids.push_back(other_pids[i]);
- }
- kill_processes(pids, will_restart);
+int ACTIVE_TASK::kill_running_task(bool will_restart) {
+ kill_app_process(pid, will_restart);
+ return 0;
+}
+
+// Clean up the subsidiary processes of a task whose main process has exited,
+// namely:
+// - its descendants (as recently enumerated; it's too late to do that now)
+// This list will be populated only in the quit and abort cases.
+// - its "other" processes, e.g. VMs
+//
+int ACTIVE_TASK::kill_subsidiary_processes() {
+ kill_processes(other_pids, true);
+ kill_processes(descendants, true);
return 0;
}
@@ -430,10 +432,8 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
//
if (task_state() == PROCESS_ABORT_PENDING) {
set_task_state(PROCESS_ABORTED, "handle_exited_app");
- kill_processes(descendants, false);
} else if (task_state() == PROCESS_QUIT_PENDING) {
set_task_state(PROCESS_UNINITIALIZED, "handle_exited_app");
- kill_processes(descendants, true);
will_restart = true;
} else {
#ifdef _WIN32
@@ -562,6 +562,8 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
#endif
}
+ // get rid of shared-mem segment and kill subsidiary processes
+ //
cleanup_task();
if (gstate.run_test_app) {
@@ -694,7 +696,7 @@ void ACTIVE_TASK_SET::process_control_poll() {
"Restarting %s - message timeout", atp->result->name
);
}
- atp->kill_task(true);
+ atp->kill_running_task(true);
} else {
atp->process_control_queue.msg_queue_poll(
atp->app_client_shm.shm->process_control_request
@@ -737,6 +739,7 @@ bool ACTIVE_TASK_SET::check_app_exited() {
// The process doesn't seem to be there.
// Mark task as aborted so we don't check it again.
//
+ atp->cleanup_task();
atp->set_task_state(PROCESS_ABORTED, "check_app_exited");
}
}
@@ -1241,7 +1244,7 @@ void ACTIVE_TASK_SET::kill_tasks(PROJECT* proj) {
atp = active_tasks[i];
if (proj && atp->wup->project != proj) continue;
if (!atp->process_exists()) continue;
- atp->kill_task(true);
+ atp->kill_running_task(true);
}
}
diff --git a/client/app_start.cpp b/client/app_start.cpp
index 58fb736..2f1826b 100644
--- a/client/app_start.cpp
+++ b/client/app_start.cpp
@@ -163,7 +163,7 @@ int ACTIVE_TASK::get_shmem_seg_name() {
char init_data_path[MAXPATHLEN];
#ifndef __EMX__
// shmem_seg_name is not used with mmap() shared memory
- if (app_version->api_major_version() >= 6) {
+ if (app_version->api_version_at_least(6, 0)) {
shmem_seg_name = -1;
return 0;
}
@@ -253,7 +253,13 @@ void ACTIVE_TASK::init_app_init_data(APP_INIT_DATA& aid) {
int rt = app_version->gpu_usage.rsc_type;
if (rt) {
COPROC& cp = coprocs.coprocs[rt];
- safe_strcpy(aid.gpu_type, cp.type);
+ if (coproc_type_name_to_num(cp.type) >= 0) {
+ // Standardized vendor name ("NVIDIA", "ATI" or "intel_gpu")
+ safe_strcpy(aid.gpu_type, cp.type);
+ } else {
+ // For other vendors, use vendor name as returned by OpenCL
+ safe_strcpy(aid.gpu_type, cp.opencl_prop.vendor);
+ }
int k = result->coproc_indices[0];
if (k<0 || k>=cp.count) {
msg_printf(0, MSG_INTERNAL_ERROR,
@@ -433,9 +439,7 @@ int ACTIVE_TASK::setup_file(
}
if (retval) return retval;
#endif
-#ifdef SANDBOX
- return set_to_project_group(link_path);
-#endif
+ if (g_use_sandbox) set_to_project_group(link_path);
return 0;
}
@@ -508,7 +512,7 @@ int ACTIVE_TASK::start(bool test) {
unsigned int i;
FILE_REF fref;
FILE_INFO* fip;
- int retval, rt;
+ int retval;
APP_INIT_DATA aid;
#ifdef _WIN32
bool success = false;
@@ -665,7 +669,8 @@ int ACTIVE_TASK::start(bool test) {
char slotdirpath[MAXPATHLEN];
char error_msg[1024];
char error_msg2[1024];
-
+ DWORD last_error;
+
memset(&process_info, 0, sizeof(process_info));
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
@@ -688,9 +693,11 @@ int ACTIVE_TASK::start(bool test) {
sprintf(cmdline, "%s %s %s",
exec_path, wup->command_line.c_str(), app_version->cmdline
);
- rt = app_version->gpu_usage.rsc_type;
- if (rt) {
- coproc_cmdline(rt, result, app_version->gpu_usage.usage, cmdline);
+ if (!app_version->api_version_at_least(7, 5)) {
+ int rt = app_version->gpu_usage.rsc_type;
+ if (rt) {
+ coproc_cmdline(rt, result, app_version->gpu_usage.usage, cmdline);
+ }
}
relative_to_absolute(slot_dir, slotdirpath);
@@ -704,6 +711,7 @@ int ACTIVE_TASK::start(bool test) {
}
for (i=0; i<5; i++) {
+ last_error = 0;
if (sandbox_account_service_token != NULL) {
if (!CreateEnvironmentBlock(&environment_block, sandbox_account_service_token, FALSE)) {
@@ -731,9 +739,11 @@ int ACTIVE_TASK::start(bool test) {
success = true;
break;
} else {
- windows_format_error_string(GetLastError(), error_msg, sizeof(error_msg));
+ last_error = GetLastError();
+ windows_format_error_string(last_error, error_msg, sizeof(error_msg));
msg_printf(wup->project, MSG_INTERNAL_ERROR,
- "Process creation failed: %s", error_msg
+ "Process creation failed: %s - error code %d (0x%x)",
+ error_msg, last_error, last_error
);
}
@@ -763,9 +773,11 @@ int ACTIVE_TASK::start(bool test) {
success = true;
break;
} else {
- windows_format_error_string(GetLastError(), error_msg, sizeof(error_msg));
+ last_error = GetLastError();
+ windows_format_error_string(last_error, error_msg, sizeof(error_msg));
msg_printf(wup->project, MSG_INTERNAL_ERROR,
- "Process creation failed: %s", error_msg
+ "Process creation failed: %s - error code %d (0x%x)",
+ error_msg, last_error, last_error
);
}
}
@@ -774,6 +786,16 @@ int ACTIVE_TASK::start(bool test) {
if (!success) {
sprintf(buf, "CreateProcess() failed - %s", error_msg);
+
+ if (last_error == ERROR_NOT_ENOUGH_MEMORY) {
+ // if CreateProcess() failed because system is low on memory,
+ // treat this like a temporary exit;
+ // retry in 10 min, and give up after 100 times
+ //
+ bool will_restart;
+ handle_temporary_exit(will_restart, 600, "not enough memory", false);
+ if (will_restart) return 0;
+ }
retval = ERR_EXEC;
goto error;
}
@@ -864,9 +886,11 @@ int ACTIVE_TASK::start(bool test) {
wup->command_line.c_str(), app_version->cmdline
);
- rt = app_version->gpu_usage.rsc_type;
- if (rt) {
- coproc_cmdline(rt, result, app_version->gpu_usage.usage, cmdline);
+ if (!app_version->api_version_at_least(7, 5)) {
+ int rt = app_version->gpu_usage.rsc_type;
+ if (rt) {
+ coproc_cmdline(rt, result, app_version->gpu_usage.usage, cmdline);
+ }
}
// Set up client/app shared memory seg if needed
@@ -875,7 +899,7 @@ int ACTIVE_TASK::start(bool test) {
#ifdef ANDROID
if (true) {
#else
- if (app_version->api_major_version() >= 6) {
+ if (app_version->api_version_at_least(6, 0)) {
#endif
// Use mmap() shared memory
sprintf(buf, "%s/%s", slot_dir, MMAPPED_FILE_NAME);
@@ -884,9 +908,7 @@ int ACTIVE_TASK::start(bool test) {
int fd = open(buf, O_RDWR | O_CREAT, 0660);
if (fd >= 0) {
close (fd);
-#ifdef SANDBOX
- set_to_project_group(buf);
-#endif
+ if (g_use_sandbox) set_to_project_group(buf);
}
}
}
diff --git a/client/client_state.cpp b/client/client_state.cpp
index e333eb4..73be34d 100644
--- a/client/client_state.cpp
+++ b/client/client_state.cpp
@@ -114,6 +114,7 @@ CLIENT_STATE::CLIENT_STATE()
core_client_version.prerelease = false;
#endif
strcpy(language, "");
+ strcpy(client_brand, "");
exit_after_app_start_secs = 0;
app_started = 0;
exit_before_upload = false;
@@ -242,6 +243,17 @@ void CLIENT_STATE::show_host_info() {
"VirtualBox version: %s",
host_info.virtualbox_version
);
+ } else {
+#if defined (_WIN32) && !defined(_WIN64)
+ if (!strcmp(get_primary_platform(), "windows_x86_64")) {
+ msg_printf(NULL, MSG_INFO,
+ "VirtualBox: can't detect because this is a 32-bit client"
+ );
+ msg_printf(NULL, MSG_INFO,
+ " (to use VirtualBox, install a 64-bit BOINC client)."
+ );
+ }
+#endif
}
}
@@ -265,7 +277,9 @@ const char* rsc_name(int i) {
// user-friendly version
//
const char* rsc_name_long(int i) {
- return proc_type_name(coproc_type_name_to_num(coprocs.coprocs[i].type));
+ int num = coproc_type_name_to_num(coprocs.coprocs[i].type);
+ if (num >= 0) return proc_type_name(num); // CPU, NVIDIA GPU, AMD GPU or Intel GPU
+ return coprocs.coprocs[i].type; // Some other type
}
// alert user if any jobs need more RAM than available
@@ -394,6 +408,14 @@ int CLIENT_STATE::init() {
msg_printf(NULL, MSG_INFO, "Running under account %s", pbuf);
#endif
+ FILE* f = fopen(CLIENT_BRAND_FILENAME, "r");
+ if (f) {
+ fgets(client_brand, sizeof(client_brand), f);
+ strip_whitespace(client_brand);
+ msg_printf(NULL, MSG_INFO, "Client brand: %s", client_brand);
+ fclose(f);
+ }
+
parse_account_files();
parse_statistics_files();
@@ -458,6 +480,8 @@ int CLIENT_STATE::init() {
coprocs.add(coprocs.intel_gpu);
}
}
+ coprocs.add_other_coproc_types();
+
host_info.coprocs = coprocs;
if (coprocs.none() ) {
@@ -659,9 +683,7 @@ int CLIENT_STATE::init() {
if (retval) return retval;
}
-#ifdef SANDBOX
- get_project_gid();
-#endif
+ if (g_use_sandbox) get_project_gid();
#ifdef _WIN32
get_sandbox_account_service_token();
if (sandbox_account_service_token != NULL) g_use_sandbox = true;
diff --git a/client/client_state.h b/client/client_state.h
index 2bcb395..8d6d3ad 100644
--- a/client/client_state.h
+++ b/client/client_state.h
@@ -110,6 +110,9 @@ struct CLIENT_STATE {
double device_status_time;
char language[16]; // ISO language code reported by GUI
+ char client_brand[256];
+ // contents of client_brand.txt, e.g. "HTP Power to Give"
+ // reported to scheduler
VERSION_INFO core_client_version;
string statefile_platform_name;
int file_xfer_giveup_period;
@@ -138,11 +141,11 @@ struct CLIENT_STATE {
// Determine when it is safe to leave the quit_client() handler
// and to finish cleaning up.
char detach_project_url[256];
- // stores URL for -detach_project option
+ // stores URL for --detach_project option
char reset_project_url[256];
- // stores URL for -reset_project option
+ // stores URL for --reset_project option
char update_prefs_url[256];
- // stores URL for -update_prefs option
+ // stores URL for --update_prefs option
char main_host_venue[256];
// venue from project or AMS that gave us general prefs
char attach_project_url[256];
diff --git a/client/client_types.cpp b/client/client_types.cpp
index a641e3d..28036ab 100644
--- a/client/client_types.cpp
+++ b/client/client_types.cpp
@@ -983,11 +983,13 @@ void APP_VERSION::clear_errors() {
}
}
-int APP_VERSION::api_major_version() {
- int v, n;
- n = sscanf(api_version, "%d", &v);
- if (n != 1) return 0;
- return v;
+bool APP_VERSION::api_version_at_least(int major, int minor) {
+ int maj, min, n;
+ n = sscanf(api_version, "%d.%d", &maj, &min);
+ if (n != 2) return false;
+ if (maj < major) return false;
+ if (maj > major) return true;
+ return min >= minor;
}
int FILE_REF::parse(XML_PARSER& xp) {
diff --git a/client/client_types.h b/client/client_types.h
index 325dd10..908b21e 100644
--- a/client/client_types.h
+++ b/client/client_types.h
@@ -282,7 +282,7 @@ struct APP_VERSION {
char api_version[16];
double avg_ncpus;
double max_ncpus;
- GPU_USAGE gpu_usage; // can only use 1 GPUtype
+ GPU_USAGE gpu_usage; // can only use 1 GPU type
double gpu_ram;
double flops;
char cmdline[256];
@@ -326,7 +326,7 @@ struct APP_VERSION {
bool had_download_failure(int& failnum);
void get_file_errors(std::string&);
void clear_errors();
- int api_major_version();
+ bool api_version_at_least(int major, int minor);
inline bool uses_coproc(int rt) {
return (gpu_usage.rsc_type == rt);
}
diff --git a/client/cpu_sched.cpp b/client/cpu_sched.cpp
index dd4177d..b54a515 100644
--- a/client/cpu_sched.cpp
+++ b/client/cpu_sched.cpp
@@ -1011,10 +1011,12 @@ static inline bool more_important(RESULT* r0, RESULT* r1) {
if (unfin0 && !unfin1) return true;
if (!unfin0 && unfin1) return false;
- // favor jobs that use more CPUs
+ // for CPU jobs, favor jobs that use more CPUs
//
- if (r0->avp->avg_ncpus > r1->avp->avg_ncpus) return true;
- if (r1->avp->avg_ncpus > r0->avp->avg_ncpus) return false;
+ if (!cp0) {
+ if (r0->avp->avg_ncpus > r1->avp->avg_ncpus) return true;
+ if (r1->avp->avg_ncpus > r0->avp->avg_ncpus) return false;
+ }
// favor jobs selected first by schedule_cpus()
// (e.g., because their project has high sched priority)
@@ -1552,17 +1554,6 @@ double CLIENT_STATE::nearly_runnable_resource_share() {
return x;
}
-bool ACTIVE_TASK::process_exists() {
- switch (task_state()) {
- case PROCESS_EXECUTING:
- case PROCESS_SUSPENDED:
- case PROCESS_ABORT_PENDING:
- case PROCESS_QUIT_PENDING:
- return true;
- }
- return false;
-}
-
// if there's not an active task for the result, make one
//
ACTIVE_TASK* CLIENT_STATE::get_task(RESULT* rp) {
diff --git a/client/cs_account.cpp b/client/cs_account.cpp
index 15ed20e..90858f2 100644
--- a/client/cs_account.cpp
+++ b/client/cs_account.cpp
@@ -206,7 +206,7 @@ int PROJECT::parse_account_file_venue() {
FILE* in = boinc_fopen(path, "r");
if (!in) return ERR_FOPEN;
- //msg_printf(this, MSG_INFO, "parsing project prefs, looking for venue %s", host_venue);
+ //msg_printf(this, MSG_INFO, "parsing project prefs, looking for venue %s", host_venue);
MIOFILE mf;
XML_PARSER xp(&mf);
mf.init_file(in);
@@ -217,7 +217,7 @@ int PROJECT::parse_account_file_venue() {
} else if (xp.match_tag("venue")) {
parse_attr(attr_buf, "name", venue, sizeof(venue));
if (!strcmp(venue, host_venue)) {
- //msg_printf(this, MSG_INFO, "found venue %s", host_venue);
+ //msg_printf(this, MSG_INFO, "found venue %s", host_venue);
using_venue_specific_prefs = true;
in_right_venue = true;
diff --git a/client/cs_cmdline.cpp b/client/cs_cmdline.cpp
index 4194df5..21520ba 100644
--- a/client/cs_cmdline.cpp
+++ b/client/cs_cmdline.cpp
@@ -68,9 +68,7 @@ static void print_options(char* prog) {
" --gui_rpc_port <port> port for GUI RPCs\n"
" --gui_rpc_unix_domain use Unix domain for GUI RPCs\n"
" --help show options\n"
-#ifdef SANDBOX
" --insecure disable app sandboxing (Unix)\n"
-#endif
#ifdef __APPLE__
" --launched_by_manager client was launched by Manager\n"
#endif
@@ -183,9 +181,7 @@ void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
print_options(argv[0]);
exit(0);
} else if (ARG(insecure)) {
-#ifdef SANDBOX
g_use_sandbox = false;
-#endif
} else if (ARG(launched_by_manager)) {
launched_by_manager = true;
} else if (ARG(master_fetch_interval)) {
diff --git a/client/cs_notice.cpp b/client/cs_notice.cpp
index ff1cb34..416d01c 100644
--- a/client/cs_notice.cpp
+++ b/client/cs_notice.cpp
@@ -345,9 +345,12 @@ bool NOTICES::remove_dups(NOTICE& n) {
) {
i = notices.erase(i);
removed_something = true;
+#if 0
+ // this check prevents news item edits from showing; skip it
} else if (same_guid(n, n2)) {
n2.keep = true;
return false;
+#endif
} else if (same_text(n, n2)) {
int min_diff = 0;
diff --git a/client/cs_scheduler.cpp b/client/cs_scheduler.cpp
index ad7f007..9a27525 100644
--- a/client/cs_scheduler.cpp
+++ b/client/cs_scheduler.cpp
@@ -125,7 +125,8 @@ int CLIENT_STATE::make_scheduler_request(PROJECT* p) {
" <prrs_fraction>%f</prrs_fraction>\n"
" <duration_correction_factor>%f</duration_correction_factor>\n"
" <allow_multiple_clients>%d</allow_multiple_clients>\n"
- " <sandbox>%d</sandbox>\n",
+ " <sandbox>%d</sandbox>\n"
+ " <dont_send_work>%d</dont_send_work>\n",
p->authenticator,
p->hostid,
p->rpc_seqno,
@@ -137,7 +138,8 @@ int CLIENT_STATE::make_scheduler_request(PROJECT* p) {
prrs_fraction,
p->duration_correction_factor,
cc_config.allow_multiple_clients?1:0,
- g_use_sandbox?1:0
+ g_use_sandbox?1:0,
+ p->dont_request_more_work?1:0
);
work_fetch.write_request(f, p);
@@ -225,28 +227,8 @@ int CLIENT_STATE::make_scheduler_request(PROJECT* p) {
total_disk_usage, p->disk_usage, p->disk_share
);
- // copy request values from RSC_WORK_FETCH to COPROC
- //
- int j = rsc_index(GPU_TYPE_NVIDIA);
- if (j > 0) {
- coprocs.nvidia.req_secs = rsc_work_fetch[j].req_secs;
- coprocs.nvidia.req_instances = rsc_work_fetch[j].req_instances;
- coprocs.nvidia.estimated_delay = rsc_work_fetch[j].req_secs?rsc_work_fetch[j].busy_time_estimator.get_busy_time():0;
- }
- j = rsc_index(GPU_TYPE_ATI);
- if (j > 0) {
- coprocs.ati.req_secs = rsc_work_fetch[j].req_secs;
- coprocs.ati.req_instances = rsc_work_fetch[j].req_instances;
- coprocs.ati.estimated_delay = rsc_work_fetch[j].req_secs?rsc_work_fetch[j].busy_time_estimator.get_busy_time():0;
- }
- j = rsc_index(GPU_TYPE_INTEL);
- if (j > 0) {
- coprocs.intel_gpu.req_secs = rsc_work_fetch[j].req_secs;
- coprocs.intel_gpu.req_instances = rsc_work_fetch[j].req_instances;
- coprocs.intel_gpu.estimated_delay = rsc_work_fetch[j].req_secs?rsc_work_fetch[j].busy_time_estimator.get_busy_time():0;
- }
-
if (coprocs.n_rsc > 1) {
+ work_fetch.copy_requests();
coprocs.write_xml(mf, true);
}
@@ -301,7 +283,7 @@ int CLIENT_STATE::make_scheduler_request(PROJECT* p) {
// send descriptions of app versions
//
fprintf(f, "<app_versions>\n");
- j=0;
+ int j=0;
for (i=0; i<app_versions.size(); i++) {
APP_VERSION* avp = app_versions[i];
if (avp->project != p) continue;
@@ -393,6 +375,10 @@ int CLIENT_STATE::make_scheduler_request(PROJECT* p) {
fclose(cof);
}
+ if (strlen(client_brand)) {
+ fprintf(f, " <client_brand>%s</client_brand>\n", client_brand);
+ }
+
fprintf(f, "</scheduler_request>\n");
fclose(f);
@@ -680,7 +666,7 @@ int CLIENT_STATE::handle_scheduler_reply(
if (sr.project_is_down) {
if (sr.request_delay) {
double x = now + sr.request_delay;
- project->set_min_rpc_time(x, "project is down");
+ project->set_min_rpc_time(x, "project requested delay");
}
return ERR_PROJECT_DOWN;
}
diff --git a/client/cs_trickle.cpp b/client/cs_trickle.cpp
index 24be21d..a8c84a7 100644
--- a/client/cs_trickle.cpp
+++ b/client/cs_trickle.cpp
@@ -70,7 +70,19 @@ int CLIENT_STATE::read_trickle_files(PROJECT* project, FILE* f) {
sprintf(path, "%s/%s", project->project_dir(), fname);
retval = read_file_malloc(path, file_contents);
- if (retval) continue;
+ if (retval) {
+ if (log_flags.trickle_debug) {
+ msg_printf(project, MSG_INFO,
+ "[trickle] can't read trickle file %s", path
+ );
+ }
+ continue;
+ }
+ if (log_flags.trickle_debug) {
+ msg_printf(project, MSG_INFO,
+ "[trickle] read trickle file %s", path
+ );
+ }
fprintf(f,
" <msg_from_host>\n"
" <result_name>%s</result_name>\n"
diff --git a/client/file_names.h b/client/file_names.h
index 0aba40f..bf729f2 100644
--- a/client/file_names.h
+++ b/client/file_names.h
@@ -62,6 +62,7 @@ extern void send_log_after(const char* filename, double t, MIOFILE& mf);
#define CA_BUNDLE_FILENAME "ca-bundle.crt"
#define CERTIFICATE_DIRECTORY "certificates"
#define CLIENT_AUTH_FILENAME "client_auth.xml"
+#define CLIENT_BRAND_FILENAME "client_brand.txt"
#define CLIENT_OPAQUE_FILENAME "client_opaque.txt"
#define CONFIG_FILE "cc_config.xml"
#define COPROC_INFO_FILENAME "coproc_info.xml"
diff --git a/client/gpu_detect.cpp b/client/gpu_detect.cpp
index d604d97..f17380f 100644
--- a/client/gpu_detect.cpp
+++ b/client/gpu_detect.cpp
@@ -37,6 +37,7 @@
#endif
#include "coproc.h"
+#include "gpu_detect.h"
#include "file_names.h"
#include "util.h"
#include "str_replace.h"
@@ -60,6 +61,7 @@ vector<COPROC_INTEL> intel_gpus;
vector<OPENCL_DEVICE_PROP> ati_opencls;
vector<OPENCL_DEVICE_PROP> nvidia_opencls;
vector<OPENCL_DEVICE_PROP> intel_gpu_opencls;
+vector<OPENCL_DEVICE_PROP> other_opencls;
vector<OPENCL_CPU_PROP> cpu_opencls;
static char* client_path;
@@ -251,6 +253,23 @@ void COPROCS::correlate_gpus(
descs.push_back(string(buf));
}
+ // Create descriptions for other OpenCL GPUs
+ //
+ int max_other_coprocs = MAX_RSC-1; // coprocs[0] is reserved for CPU
+ if (have_nvidia()) max_other_coprocs--;
+ if (have_ati()) max_other_coprocs--;
+ if (have_intel_gpu()) max_other_coprocs--;
+
+ // TODO: Should we implement cc_config ignore vectors for other (future) OpenCL coprocessors?
+
+ for (i=0; i<other_opencls.size(); i++) {
+ if ((int)i > max_other_coprocs) {
+ other_opencls[i].is_used = COPROC_UNUSED;
+ }
+ other_opencls[i].description(buf, sizeof(buf), other_opencls[i].name);
+ descs.push_back(string(buf));
+ }
+
// Create descriptions for OpenCL CPUs
//
for (i=0; i<cpu_opencls.size(); i++) {
@@ -265,7 +284,43 @@ void COPROCS::correlate_gpus(
nvidia_opencls.clear();
intel_gpu_opencls.clear();
cpu_opencls.clear();
+}
+// This is called from CLIENT_STATE::init() after adding NVIDIA, ATI and Intel GPUs
+// If we don't care about the order of GPUs in COPROCS::coprocs[],
+// this code could be included at the end of COPROCS::correlate_gpus().
+int COPROCS::add_other_coproc_types() {
+ int retval = 0;
+
+ for (unsigned int i=0; i<other_opencls.size(); i++) {
+ if (other_opencls[i].is_used != COPROC_USED) continue;
+ if (n_rsc >= MAX_RSC) {
+ retval = ERR_BUFFER_OVERFLOW;
+ break;
+ }
+
+ COPROC c;
+ // For other device types other than NVIDIA, ATI or Intel GPU coprocessor.
+ // we put each instance into a separate other_opencls element, so count=1.
+ c.count = 1;
+ c.opencl_device_count = 1;
+ c.opencl_prop = other_opencls[i];
+ c.available_ram = c.opencl_prop.global_mem_size;
+ c.device_num = c.opencl_prop.device_num;
+ c.peak_flops = c.opencl_prop.peak_flops;
+ c.have_opencl = true;
+ c.opencl_device_indexes[0] = c.opencl_prop.opencl_device_index;
+ c.opencl_device_ids[0] = c.opencl_prop.device_id;
+ c.instance_has_opencl[0] = true;
+ safe_strcpy(c.type, other_opencls[i].name);
+
+ // Don't call COPROCS::add() because duplicate type is legal here
+ coprocs[n_rsc++] = c;
+
+ }
+
+ other_opencls.clear();
+ return retval;
}
// Some dual-GPU laptops (e.g., Macbook Pro) don't
@@ -316,6 +371,9 @@ int COPROCS::write_coproc_info_file(vector<string> &warnings) {
for (i=0; i<intel_gpu_opencls.size(); ++i) {
intel_gpu_opencls[i].write_xml(mf, "intel_gpu_opencl", true);
}
+ for (i=0; i<other_opencls.size(); i++) {
+ other_opencls[i].write_xml(mf, "other_opencl", true);
+ }
for (i=0; i<cpu_opencls.size(); i++) {
cpu_opencls[i].write_xml(mf);
}
@@ -340,6 +398,7 @@ int COPROCS::read_coproc_info_file(vector<string> &warnings) {
OPENCL_DEVICE_PROP ati_opencl;
OPENCL_DEVICE_PROP nvidia_opencl;
OPENCL_DEVICE_PROP intel_gpu_opencl;
+ OPENCL_DEVICE_PROP other_opencl;
OPENCL_CPU_PROP cpu_opencl;
ati_gpus.clear();
@@ -348,6 +407,7 @@ int COPROCS::read_coproc_info_file(vector<string> &warnings) {
ati_opencls.clear();
nvidia_opencls.clear();
intel_gpu_opencls.clear();
+ other_opencls.clear();
cpu_opencls.clear();
f = boinc_fopen(COPROC_INFO_FILENAME, "r");
@@ -434,6 +494,18 @@ int COPROCS::read_coproc_info_file(vector<string> &warnings) {
continue;
}
+ if (xp.match_tag("other_opencl")) {
+ memset(&other_opencl, 0, sizeof(other_opencl));
+ retval = other_opencl.parse(xp, "/other_opencl");
+ if (retval) {
+ memset(&other_opencl, 0, sizeof(other_opencl));
+ } else {
+ other_opencl.is_used = COPROC_USED;
+ other_opencls.push_back(other_opencl);
+ }
+ continue;
+ }
+
if (xp.match_tag("opencl_cpu_prop")) {
memset(&cpu_opencl, 0, sizeof(cpu_opencl));
retval = cpu_opencl.parse(xp);
@@ -528,7 +600,11 @@ int COPROCS::launch_child_process_to_detect_gpus() {
client_path,
argc,
argv,
+#ifdef _DEBUG
+ 1,
+#else
0,
+#endif
prog
);
diff --git a/client/gpu_detect.h b/client/gpu_detect.h
index 366a1bc..75b32a6 100644
--- a/client/gpu_detect.h
+++ b/client/gpu_detect.h
@@ -15,11 +15,20 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
+#ifndef _GPU_DETECT_H_
+#define _GPU_DETECT_H_
+
+#include "coproc.h"
+
+using std::vector;
+
extern vector<COPROC_ATI> ati_gpus;
extern vector<COPROC_NVIDIA> nvidia_gpus;
extern vector<COPROC_INTEL> intel_gpus;
extern vector<OPENCL_DEVICE_PROP> nvidia_opencls;
extern vector<OPENCL_DEVICE_PROP> ati_opencls;
extern vector<OPENCL_DEVICE_PROP> intel_gpu_opencls;
+extern vector<OPENCL_DEVICE_PROP> other_opencls;
extern vector<OPENCL_CPU_PROP> cpu_opencls;
+#endif
diff --git a/client/gpu_opencl.cpp b/client/gpu_opencl.cpp
index 3902b3a..2ba3a14 100644
--- a/client/gpu_opencl.cpp
+++ b/client/gpu_opencl.cpp
@@ -17,6 +17,8 @@
// Detection of GPUs using OpenCL
+#define TEST_OTHER_COPROC_LOGIC 0
+
#ifdef _WIN32
#include "boinc_win.h"
#ifdef _MSC_VER
@@ -176,7 +178,6 @@ void COPROCS::get_opencl(
#ifdef __APPLE__
opencl_lib = dlopen("/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", RTLD_NOW);
#else
-//TODO: Is this correct?
opencl_lib = dlopen("libOpenCL.so", RTLD_NOW);
#endif
if (!opencl_lib) {
@@ -289,10 +290,11 @@ void COPROCS::get_opencl(
cpu_opencls.push_back(c);
}
- //////////// GPUs //////////////
+ //////////// GPUs and Accelerators //////////////
ciErrNum = (*__clGetDeviceIDs)(
- platforms[platform_index], (CL_DEVICE_TYPE_GPU),
+ platforms[platform_index],
+ (CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR),
MAX_COPROC_INSTANCES, devices, &num_devices
);
@@ -367,6 +369,17 @@ void COPROCS::get_opencl(
ciErrNum = get_opencl_info(prop, device_index, warnings);
if (ciErrNum != CL_SUCCESS) continue;
+// TODO: Eliminate this, or improve it
+#if TEST_OTHER_COPROC_LOGIC
+ if (is_NVIDIA(prop.vendor)) {
+ safe_strcpy(prop.vendor, "FAKE VENDOR X");
+ } else if (is_AMD(prop.vendor)) {
+ safe_strcpy(prop.vendor, "FAKE VENDOR Y");
+ } else {
+ safe_strcpy(prop.vendor, "FAKE VENDOR Z");
+ }
+#endif
+
prop.is_used = COPROC_UNUSED;
prop.get_device_version_int();
@@ -432,7 +445,7 @@ void COPROCS::get_opencl(
}
//////////// AMD / ATI //////////////
- if (is_AMD(prop.vendor)) {
+ else if (is_AMD(prop.vendor)) {
prop.opencl_device_index = device_index;
if (ati.have_cal) {
@@ -490,8 +503,7 @@ void COPROCS::get_opencl(
}
//////////// INTEL GPU //////////////
- //
- if (is_intel(prop.vendor)) {
+ else if (is_intel(prop.vendor)) {
prop.device_num = (int)(intel_gpu_opencls.size());
prop.opencl_device_index = device_index;
@@ -515,8 +527,47 @@ void COPROCS::get_opencl(
//
intel_gpus.push_back(c);
}
+
+ //////////// OTHER GPU OR ACCELERTOR //////////////
+ else {
+ // Put each coprocessor instance into a separate other_opencls element
+
+ // opencl_device_index is passed to project apps via init_data.xml
+ // to differentiate among OpenCL devices from the same vendor. It is
+ // used by boinc_get_opencl_ids() to select the correct OpenCL device.
+ int opencl_device_index = 0;
+ for (unsigned int coproc_index=0; coproc_index<other_opencls.size(); coproc_index++) {
+ if (!strcmp(other_opencls[coproc_index].vendor, prop.vendor)) {
+ opencl_device_index++; // Another OpenCL device from same vendor
+ }
+ }
+
+ prop.device_num = 0; // Each vector entry has only one device
+ prop.opencl_device_index = opencl_device_index;
+ prop.opencl_available_ram = prop.global_mem_size;
+ prop.is_used = COPROC_USED;
+
+ // TODO: Find a better way to calculate / estimate peak_flops for future coprocessors?
+ prop.peak_flops = 0;
+ if (prop.max_compute_units) {
+ prop.peak_flops = prop.max_compute_units * prop.max_clock_frequency * MEGA;
+ }
+ if (prop.peak_flops <= 0) prop.peak_flops = 45e9;
+
+ other_opencls.push_back(prop);
+ }
}
}
+
+ int max_other_coprocs = MAX_RSC-1; // coprocs[0] is reserved for CPU
+ // Neither nvidia.count, ati.count nor intel_gpu.count have been set yet,
+ // so we can't test have_nvidia(), have_ati() or have_intel_gpu() here.
+ if ((nvidia_opencls.size() > 0) || nvidia.have_cuda) max_other_coprocs--;
+ if ((ati_opencls.size() > 0) || ati.have_cal) max_other_coprocs--;
+ if (intel_gpu_opencls.size() > 0) max_other_coprocs--;
+ if ((int)other_opencls.size() > max_other_coprocs) {
+ warnings.push_back("Too many OpenCL device types found");
+ }
#ifdef __APPLE__
@@ -532,10 +583,12 @@ void COPROCS::get_opencl(
if ((nvidia_opencls.size() == 0) &&
(ati_opencls.size() == 0) &&
- (intel_gpu_opencls.size() == 0)
+ (intel_gpu_opencls.size() == 0) &&
+ (cpu_opencls.size() == 0) &&
+ (other_opencls.size() == 0)
) {
warnings.push_back(
- "OpenCL library present but no OpenCL-capable GPUs found"
+ "OpenCL library present but no OpenCL-capable devices found"
);
}
}
@@ -577,9 +630,7 @@ void COPROCS::correlate_opencl(
intel_gpu.available_ram = intel_gpu.opencl_prop.global_mem_size;
safe_strcpy(intel_gpu.name, intel_gpu.opencl_prop.name);
}
-
-// TODO: Add code to allow adding other GPU vendors
-}
+ }
cl_int COPROCS::get_opencl_info(
OPENCL_DEVICE_PROP& prop,
@@ -839,7 +890,7 @@ void COPROC::find_best_opencls(
) {
unsigned int i;
- // identify the most capable ATI or NVIDIA OpenCL GPU
+ // identify the most capable ATI, NVIDIA or Intel OpenCL GPU
//
bool first = true;
for (i=0; i<opencls.size(); i++) {
diff --git a/client/project.cpp b/client/project.cpp
index 906c05e..555a0d7 100644
--- a/client/project.cpp
+++ b/client/project.cpp
@@ -60,6 +60,7 @@ void PROJECT::init() {
strcpy(team_name, "");
strcpy(email_hash, "");
strcpy(cross_project_id, "");
+ strcpy(external_cpid, "");
cpid_time = 0;
user_total_credit = 0;
user_expavg_credit = 0;
@@ -106,6 +107,7 @@ void PROJECT::init() {
too_many_uploading_results = false;
njobs_success = 0;
njobs_error = 0;
+ app_configs.clear();
#ifdef SIM
idle_time = 0;
@@ -190,6 +192,7 @@ int PROJECT::parse_state(XML_PARSER& xp) {
if (xp.parse_str("host_venue", host_venue, sizeof(host_venue))) continue;
if (xp.parse_str("email_hash", email_hash, sizeof(email_hash))) continue;
if (xp.parse_str("cross_project_id", cross_project_id, sizeof(cross_project_id))) continue;
+ if (xp.parse_str("external_cpid", external_cpid, sizeof(external_cpid))) continue;
if (xp.parse_double("cpid_time", cpid_time)) continue;
if (xp.parse_double("user_total_credit", user_total_credit)) continue;
if (xp.parse_double("user_expavg_credit", user_expavg_credit)) continue;
@@ -352,6 +355,7 @@ int PROJECT::write_state(MIOFILE& out, bool gui_rpc) {
" <host_venue>%s</host_venue>\n"
" <email_hash>%s</email_hash>\n"
" <cross_project_id>%s</cross_project_id>\n"
+ " <external_cpid>%s</external_cpid>\n"
" <cpid_time>%f</cpid_time>\n"
" <user_total_credit>%f</user_total_credit>\n"
" <user_expavg_credit>%f</user_expavg_credit>\n"
@@ -386,6 +390,7 @@ int PROJECT::write_state(MIOFILE& out, bool gui_rpc) {
host_venue,
email_hash,
cross_project_id,
+ external_cpid,
cpid_time,
user_total_credit,
user_expavg_credit,
@@ -521,6 +526,7 @@ void PROJECT::copy_state_fields(PROJECT& p) {
safe_strcpy(host_venue, p.host_venue);
safe_strcpy(email_hash, p.email_hash);
safe_strcpy(cross_project_id, p.cross_project_id);
+ safe_strcpy(external_cpid, p.external_cpid);
user_total_credit = p.user_total_credit;
user_expavg_credit = p.user_expavg_credit;
user_create_time = p.user_create_time;
diff --git a/client/project.h b/client/project.h
index 70cb63b..1b42f90 100644
--- a/client/project.h
+++ b/client/project.h
@@ -95,6 +95,9 @@ struct PROJECT : PROJ_AM {
char team_name[256];
char email_hash[MD5_LEN];
char cross_project_id[MD5_LEN];
+ // the "internal" user CPID
+ char external_cpid[MD5_LEN];
+ // the "external" user CPID (as exported to stats sites)
double cpid_time;
double user_total_credit;
double user_expavg_credit;
@@ -229,6 +232,8 @@ struct PROJECT : PROJ_AM {
bool some_result_suspended();
bool uploading();
bool has_results();
+ int n_concurrent;
+ // used to enforce APP_CONFIGS::max_concurrent
struct RESULT *next_runnable_result;
// the next result to run for this project
diff --git a/client/result.h b/client/result.h
index 0a9c91d..aa39d88 100644
--- a/client/result.h
+++ b/client/result.h
@@ -167,6 +167,7 @@ struct RESULT {
bool already_selected;
// used to keep cpu scheduler from scheduling a result twice
// transient; used only within schedule_cpus()
+ // also used in round-robin simulation
double computation_deadline();
// report deadline - prefs.work_buf_min - time slice
bool rr_sim_misses_deadline;
@@ -190,13 +191,23 @@ struct RESULT {
inline bool max_concurrent_exceeded(RESULT* rp) {
APP* app = rp->app;
- if (!app->max_concurrent) return false;
- return (app->n_concurrent >= app->max_concurrent);
-
+ if (app->max_concurrent) {
+ if (app->n_concurrent >= app->max_concurrent) {
+ return true;
+ }
+ }
+ PROJECT* p = rp->project;
+ if (p->app_configs.project_max_concurrent) {
+ if (p->n_concurrent >= p->app_configs.project_max_concurrent) {
+ return true;
+ }
+ }
+ return false;
}
inline void max_concurrent_inc(RESULT* rp) {
rp->app->n_concurrent++;
+ rp->project->n_concurrent++;
}
// a completed result, for which the RESULT record no longer exists.
diff --git a/client/rr_sim.cpp b/client/rr_sim.cpp
index 9027669..d0f1c0f 100644
--- a/client/rr_sim.cpp
+++ b/client/rr_sim.cpp
@@ -180,6 +180,7 @@ void RR_SIM::init_pending_lists() {
for (unsigned int i=0; i<gstate.results.size(); i++) {
RESULT* rp = gstate.results[i];
rp->rr_sim_misses_deadline = false;
+ rp->already_selected = false;
if (!rp->nearly_runnable()) continue;
if (rp->some_download_stalled()) continue;
if (rp->project->non_cpu_intensive) continue;
@@ -268,13 +269,14 @@ void RR_SIM::pick_jobs_to_run(double reltime) {
//
activate(rp);
adjust_rec_sched(rp);
- if (log_flags.rrsim_detail) {
+ if (log_flags.rrsim_detail && !rp->already_selected) {
char buf[256];
rsc_string(rp, buf);
msg_printf(rp->project, MSG_INFO,
- "[rr_sim_detail] %.2f: starting %s (%s)",
- reltime, rp->name, buf
+ "[rr_sim_detail] %.2f: starting %s (%s) (%.2fG/%.2fG)",
+ reltime, rp->name, buf, rp->rrsim_flops_left/1e9, rp->rrsim_flops/1e9
);
+ rp->already_selected = true;
}
// check whether resource is saturated
@@ -412,6 +414,13 @@ void RR_SIM::simulate() {
// see if we finish a time slice before first job ends
//
double delta_t = rpbest->rrsim_finish_delay;
+ if (log_flags.rrsim_detail) {
+ msg_printf(NULL, MSG_INFO,
+ "[rrsim_detail] rpbest: %s (finish delay %.2f)",
+ rpbest->name,
+ delta_t
+ );
+ }
if (delta_t > 3600) {
rpbest = 0;
@@ -422,14 +431,22 @@ void RR_SIM::simulate() {
} else {
delta_t = 3600;
}
+ if (log_flags.rrsim_detail) {
+ msg_printf(NULL, MSG_INFO,
+ "[rrsim_detail] time-slice step of %.2f sec", delta_t
+ );
+ }
} else {
rpbest->rrsim_done = true;
pbest = rpbest->project;
if (log_flags.rr_simulation) {
+ char buf[256];
+ rsc_string(rpbest, buf);
msg_printf(pbest, MSG_INFO,
- "[rr_sim] %.2f: %s finishes (%.2fG/%.2fG)",
- sim_now - gstate.now,
+ "[rr_sim] %.2f: %s finishes (%s) (%.2fG/%.2fG)",
+ sim_now + delta_t - gstate.now,
rpbest->name,
+ buf,
rpbest->estimated_flops_remaining()/1e9, rpbest->rrsim_flops/1e9
);
}
@@ -472,30 +489,9 @@ void RR_SIM::simulate() {
}
}
-#if 1
for (int i=0; i<coprocs.n_rsc; i++) {
rsc_work_fetch[i].update_stats(sim_now, delta_t, buf_end);
}
-#else
- // update saturated time
- //
- double end_time = sim_now + delta_t;
- double x = end_time - gstate.now;
- for (int i=0; i<coprocs.n_rsc; i++) {
- rsc_work_fetch[i].update_saturated_time(x);
- }
-
- // increment resource shortfalls
- //
- if (sim_now < buf_end) {
- if (end_time > buf_end) end_time = buf_end;
- double d_time = end_time - sim_now;
-
- for (int i=0; i<coprocs.n_rsc; i++) {
- rsc_work_fetch[i].accumulate_shortfall(d_time);
- }
- }
-#endif
// update project REC
//
diff --git a/client/sandbox.cpp b/client/sandbox.cpp
index ff6ff93..df215e8 100644
--- a/client/sandbox.cpp
+++ b/client/sandbox.cpp
@@ -23,8 +23,10 @@
#include "config.h"
#include <sys/types.h>
#include <sys/wait.h>
-#include <grp.h>
#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <grp.h>
#endif
#include "error_numbers.h"
@@ -42,49 +44,6 @@
bool g_use_sandbox = false;
#ifndef _WIN32
-#ifndef _DEBUG
-static int lookup_group(const char* name, gid_t& gid) {
- struct group* gp = getgrnam(name);
- if (!gp) return ERR_GETGRNAM;
- gid = gp->gr_gid;
- return 0;
-}
-#endif
-
-int kill_via_switcher(int pid) {
- char cmd[1024];
-
- if (!g_use_sandbox) return 0;
-
- // if project application is running as user boinc_project and
- // client is running as user boinc_master,
- // we cannot send a signal directly, so use switcher.
- //
- sprintf(cmd, "/bin/kill kill -s KILL %d", pid);
- return switcher_exec(SWITCHER_FILE_NAME, cmd);
-}
-
-int get_project_gid() {
- if (g_use_sandbox) {
-#ifdef _DEBUG
- gstate.boinc_project_gid = getegid();
-#else
- return lookup_group(BOINC_PROJECT_GROUP_NAME, gstate.boinc_project_gid);
-#endif // _DEBUG
- } else {
- gstate.boinc_project_gid = 0;
- }
- return 0;
-}
-
-int set_to_project_group(const char* path) {
- if (g_use_sandbox) {
- if (switcher_exec(SETPROJECTGRP_FILE_NAME, path)) {
- return ERR_CHOWN;
- }
- }
- return 0;
-}
// POSIX requires that shells run from an application will use the
// real UID and GID if different from the effective UID and GID.
@@ -95,10 +54,30 @@ int set_to_project_group(const char* path) {
int switcher_exec(const char *util_filename, const char* cmdline) {
char* argv[100];
char util_path[MAXPATHLEN];
+ char command [1024];
+ char buffer[1024];
+ int fds_out[2], fds_err[2];
+ int stat;
+ int retval;
+ std::string output_out, output_err;
sprintf(util_path, "%s/%s", SWITCHER_DIR, util_filename);
argv[0] = const_cast<char*>(util_filename);
+ // Make a copy of cmdline because parse_command_line modifies it
+ safe_strcpy(command, cmdline);
parse_command_line(const_cast<char*>(cmdline), argv+1);
+
+ // Create the output pipes
+ if (pipe(fds_out) == -1) {
+ perror("pipe() for fds_out failed in switcher_exec");
+ return ERR_PIPE;
+ }
+
+ if (pipe(fds_err) == -1) {
+ perror("pipe() for fds_err failed in switcher_exec");
+ return ERR_PIPE;
+ }
+
int pid = fork();
if (pid == -1) {
perror("fork() failed in switcher_exec");
@@ -106,15 +85,105 @@ int switcher_exec(const char *util_filename, const char* cmdline) {
}
if (pid == 0) {
// This is the new (forked) process
+
+ // Setup pipe redirects
+ while ((dup2(fds_out[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+ while ((dup2(fds_err[1], STDERR_FILENO) == -1) && (errno == EINTR)) {}
+ // Child only needs one-way (write) pipes so close read pipes
+ close(fds_out[0]);
+ close(fds_err[0]);
+
execv(util_path, argv);
fprintf(stderr, "execv failed in switcher_exec(%s, %s): %s", util_path, cmdline, strerror(errno));
- return ERR_EXEC;
+
+ _exit(EXIT_FAILURE);
+ }
+ // Parent only needs one-way (read) pipes so close write pipes
+ close(fds_out[1]);
+ close(fds_err[1]);
+
+ // Capture stdout output
+ while (1) {
+ ssize_t count = read(fds_out[0], buffer, sizeof(buffer));
+ if (count == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ } else if (count == 0) {
+ break;
+ } else {
+ buffer[count] = '\0';
+ output_out += buffer;
+ }
+ }
+
+ // Capture stderr output
+ while (1) {
+ ssize_t count = read(fds_err[0], buffer, sizeof(buffer));
+ if (count == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ } else if (count == 0) {
+ break;
+ } else {
+ buffer[count] = '\0';
+ output_err += buffer;
+ }
}
+
// Wait for command to complete, like system() does.
- waitpid(pid, 0, 0);
+ waitpid(pid, &stat, 0);
+
+ // Close pipe descriptors
+ close(fds_out[0]);
+ close(fds_err[0]);
+
+ if (WIFEXITED(stat)) {
+ retval = WEXITSTATUS(stat);
+
+ if (retval) {
+ if (log_flags.task_debug) {
+ msg_printf(0, MSG_INTERNAL_ERROR, "[task_debug] failure in switcher_exec");
+ msg_printf(0, MSG_INTERNAL_ERROR, "[task_debug] switcher: %s", util_path);
+ msg_printf(0, MSG_INTERNAL_ERROR, "[task_debug] command: %s", command);
+ msg_printf(0, MSG_INTERNAL_ERROR, "[task_debug] exit code: %d", retval);
+ msg_printf(0, MSG_INTERNAL_ERROR, "[task_debug] stdout: %s", output_out.c_str());
+ msg_printf(0, MSG_INTERNAL_ERROR, "[task_debug] stderr: %s", output_err.c_str());
+ }
+ }
+ return retval;
+ }
+
return 0;
}
+int kill_via_switcher(int pid) {
+ char cmd[1024];
+
+ if (!g_use_sandbox) return 0;
+
+ // if project application is running as user boinc_project and
+ // client is running as user boinc_master,
+ // we cannot send a signal directly, so use switcher.
+ //
+ sprintf(cmd, "/bin/kill kill -s KILL %d", pid);
+ return switcher_exec(SWITCHER_FILE_NAME, cmd);
+}
+
+#ifndef _DEBUG
+static int lookup_group(const char* name, gid_t& gid) {
+ struct group* gp = getgrnam(name);
+ if (!gp) return ERR_GETGRNAM;
+ gid = gp->gr_gid;
+ return 0;
+}
+#endif
+
int remove_project_owned_file_or_dir(const char* path) {
char cmd[1024];
@@ -129,6 +198,37 @@ int remove_project_owned_file_or_dir(const char* path) {
return ERR_UNLINK;
}
+int get_project_gid() {
+ if (g_use_sandbox) {
+#ifdef _DEBUG
+ // GDB can't attach to applications which are running as a different user
+ // or group, so fix up data with current user and group during debugging
+ gstate.boinc_project_gid = getegid();
+#else
+ return lookup_group(BOINC_PROJECT_GROUP_NAME, gstate.boinc_project_gid);
+#endif // _DEBUG
+ } else {
+ gstate.boinc_project_gid = 0;
+ }
+ return 0;
+}
+
+int set_to_project_group(const char* path) {
+ if (g_use_sandbox) {
+ if (switcher_exec(SETPROJECTGRP_FILE_NAME, path)) {
+ return ERR_CHOWN;
+ }
+ }
+ return 0;
+}
+
+#else
+int get_project_gid() {
+ return 0;
+}
+int set_to_project_group(const char* path) {
+ return 0;
+}
#endif // ! _WIN32
static int delete_project_owned_file_aux(const char* path) {
diff --git a/client/scheduler_op.cpp b/client/scheduler_op.cpp
index 6a05cfa..edc39fc 100644
--- a/client/scheduler_op.cpp
+++ b/client/scheduler_op.cpp
@@ -824,6 +824,8 @@ int SCHEDULER_REPLY::parse(FILE* in, PROJECT* project) {
continue;
} else if (xp.parse_str("cross_project_id", project->cross_project_id, sizeof(project->cross_project_id))) {
continue;
+ } else if (xp.parse_str("external_cpid", project->external_cpid, sizeof(project->external_cpid))) {
+ continue;
} else if (xp.match_tag("trickle_down")) {
retval = gstate.handle_trickle_down(project, in);
if (retval) {
diff --git a/client/sim.cpp b/client/sim.cpp
index 4bf0c3c..1056a64 100644
--- a/client/sim.cpp
+++ b/client/sim.cpp
@@ -897,8 +897,6 @@ void show_resource(int rsc_type) {
fprintf(html_out, "</table></td>");
}
-int nproc_types = 1;
-
void html_start() {
char buf[256];
@@ -921,13 +919,16 @@ void html_start() {
fprintf(html_out,
"<th width=%d>CPU</th>", WIDTH2
);
- if (coprocs.have_nvidia()) {
- fprintf(html_out, "<th width=%d>NVIDIA GPU</th>", WIDTH2);
- nproc_types++;
- }
- if (coprocs.have_ati()) {
- fprintf(html_out, "<th width=%d>ATI GPU</th>", WIDTH2);
- nproc_types++;
+ for (int i=1; i<coprocs.n_rsc; i++) {
+ int pt = coproc_type_name_to_num(coprocs.coprocs[i].type);
+ const char* name;
+ if (pt) {
+ name = proc_type_name(pt);
+ } else {
+ name = coprocs.coprocs[i].type;
+ }
+ fprintf(html_out, "<th width=%d>%s</th>\n", WIDTH2, name);
+
}
fprintf(html_out, "</tr></table>\n");
}
@@ -940,7 +941,7 @@ void html_rec() {
);
fprintf(html_out,
"<td width=%d valign=top><font size=-2>%s</font></td></tr></table>\n",
- nproc_types*WIDTH2,
+ coprocs.n_rsc*WIDTH2,
html_msg.c_str()
);
html_msg = "";
diff --git a/client/switcher.cpp b/client/switcher.cpp
index 7bc1aa8..1902350 100644
--- a/client/switcher.cpp
+++ b/client/switcher.cpp
@@ -130,9 +130,11 @@ int main(int /*argc*/, char** argv) {
#endif
}
- execv(argv[1], argv+2);
-
- // If we got here execv failed
- fprintf(stderr, "Process creation (%s) failed: errno=%d\n", argv[1], errno);
+ retval = execv(argv[1], argv+2);
+ if (retval == -1) {
+ // If we got here execv failed
+ fprintf(stderr, "Process creation (%s) failed: %s (errno = %d)\n", argv[1], strerror(errno), retval);
+ }
+ return retval;
}
diff --git a/client/work_fetch.cpp b/client/work_fetch.cpp
index ee7ed06..1fc6078 100644
--- a/client/work_fetch.cpp
+++ b/client/work_fetch.cpp
@@ -15,6 +15,8 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
+#include <cmath>
+
#include "cpp.h"
#ifdef _WIN32
@@ -146,6 +148,12 @@ void RSC_PROJECT_WORK_FETCH::resource_backoff(PROJECT* p, const char* name) {
/////////////// RSC_WORK_FETCH ///////////////
+void RSC_WORK_FETCH::copy_request(COPROC& c) {
+ c.req_secs = req_secs;
+ c.req_instances = req_instances;
+ c.estimated_delay = req_secs?busy_time_estimator.get_busy_time():0;
+}
+
RSC_PROJECT_WORK_FETCH& RSC_WORK_FETCH::project_state(PROJECT* p) {
return p->rsc_pwf[rsc_type];
}
@@ -421,6 +429,27 @@ void WORK_FETCH::set_all_requests(PROJECT* p) {
}
#endif
+// copy request fields from RSC_WORK_FETCH to COPROCS
+//
+void WORK_FETCH::copy_requests() {
+ for (int i=0; i<coprocs.n_rsc; i++) {
+ switch (coproc_type_name_to_num(coprocs.coprocs[i].type)) {
+ case PROC_TYPE_NVIDIA_GPU:
+ rsc_work_fetch[i].copy_request(coprocs.nvidia);
+ break;
+ case PROC_TYPE_AMD_GPU:
+ rsc_work_fetch[i].copy_request(coprocs.ati);
+ break;
+ case PROC_TYPE_INTEL_GPU:
+ rsc_work_fetch[i].copy_request(coprocs.intel_gpu);
+ break;
+ default:
+ rsc_work_fetch[i].copy_request(coprocs.coprocs[i]);
+ break;
+ }
+ }
+}
+
void WORK_FETCH::print_state() {
msg_printf(0, MSG_INFO, "[work_fetch] ------- start work fetch state -------");
msg_printf(0, MSG_INFO, "[work_fetch] target work buffer: %.2f + %.2f sec",
@@ -530,7 +559,7 @@ void WORK_FETCH::piggyback_work_request(PROJECT* p) {
for (unsigned int j=0; j<gstate.projects.size(); j++) {
p2 = gstate.projects[j];
if (p2 == p) break;
- if (p2->sched_priority == p->sched_priority) continue;
+ if (p2->sched_priority == p->sched_priority) continue;
if (p2->pwf.cant_fetch_work_reason) {
WF_DEBUG(msg_printf(p, MSG_INFO, "piggyback: %s can't fetch work", p2->project_name);)
continue;
@@ -1054,13 +1083,25 @@ void CLIENT_STATE::compute_nuploading_results() {
double ACTIVE_TASK::est_dur() {
if (fraction_done >= 1) return elapsed_time;
double wu_est = result->estimated_runtime();
- if (wu_est < elapsed_time) wu_est = elapsed_time;
- if (fraction_done <= 0) return wu_est;
+ if (fraction_done <= 0) {
+ if (elapsed_time > 0) {
+ // if app is running but hasn't reported fraction done,
+ // use the fraction-done guesstimate from ACTIVE_TASK::write_gui()
+ //
+ double fd = 1 - exp(-elapsed_time/wu_est);
+ return elapsed_time/fd;
+ } else {
+ return wu_est;
+ }
+ }
+ bool exceeded_wu_est = (elapsed_time > wu_est);
+ if (exceeded_wu_est) wu_est = elapsed_time;
double frac_est = fraction_done_elapsed_time / fraction_done;
// if app says fraction done is accurate, just use it
+ // also use it if static estimate has already been exceeded
//
- if (result->app->fraction_done_exact) return frac_est;
+ if (result->app->fraction_done_exact || exceeded_wu_est) return frac_est;
// weighting of dynamic estimate is the fraction done
// i.e. when fraction done is 0.5, weighting is 50/50
diff --git a/client/work_fetch.h b/client/work_fetch.h
index b58a771..a2d0e23 100644
--- a/client/work_fetch.h
+++ b/client/work_fetch.h
@@ -240,6 +240,7 @@ struct RSC_WORK_FETCH {
void print_state(const char*);
void clear_request();
void set_request(PROJECT*);
+ void copy_request(COPROC&);
void set_request_excluded(PROJECT*);
bool may_have_work(PROJECT*);
int cant_fetch(PROJECT*);
@@ -311,6 +312,7 @@ struct WORK_FETCH {
void clear_backoffs(APP_VERSION&);
void request_string(char*);
bool requested_work();
+ void copy_requests();
};
extern RSC_WORK_FETCH rsc_work_fetch[MAX_RSC];
diff --git a/clientgui/DlgAdvPreferences.cpp b/clientgui/DlgAdvPreferences.cpp
index 8a4b23a..715d7a3 100644
--- a/clientgui/DlgAdvPreferences.cpp
+++ b/clientgui/DlgAdvPreferences.cpp
@@ -100,6 +100,29 @@ CDlgAdvPreferences::CDlgAdvPreferences(wxWindow* parent) : CDlgAdvPreferencesBas
ReadPreferenceSettings();
//
RestoreState();
+
+#ifdef __WXMSW__
+ int margin = 0, tabwidth = 0;
+ RECT r;
+ BOOL success = TabCtrl_GetItemRect(m_Notebook->GetHWND(), 0, &r);
+ if (success) {
+ margin = r.left;
+ }
+
+ success = TabCtrl_GetItemRect(m_Notebook->GetHWND(), m_Notebook->GetPageCount()-1, &r);
+ if (success) {
+ tabwidth += r.right;
+ }
+ tabwidth += margin;
+ wxSize sz = m_Notebook->GetBestSize();
+ if (sz.x < tabwidth) {
+ sz.x = tabwidth;
+ m_Notebook->SetMinSize(sz);
+ }
+#endif
+
+ this->Layout();
+ Fit();
}
/* destructor */
@@ -779,7 +802,10 @@ bool CDlgAdvPreferences::EnsureTabPageVisible(wxTextCtrl* txtCtrl) {
/* show an error message and set the focus to the control that caused the error */
void CDlgAdvPreferences::ShowErrorMessage(wxString& message,wxTextCtrl* errorCtrl) {
- bool visibleOK = this->EnsureTabPageVisible(errorCtrl);
+#if wxDEBUG_LEVEL // Prevent compiler warning (unused variable)
+ bool visibleOK =
+#endif
+ this->EnsureTabPageVisible(errorCtrl);
wxASSERT(visibleOK);
//
if(message.IsEmpty()){
diff --git a/clientgui/DlgAdvPreferencesBase.cpp b/clientgui/DlgAdvPreferencesBase.cpp
index 9876dfd..e8deae1 100644
--- a/clientgui/DlgAdvPreferencesBase.cpp
+++ b/clientgui/DlgAdvPreferencesBase.cpp
@@ -98,6 +98,7 @@ CDlgAdvPreferencesBase::CDlgAdvPreferencesBase( wxWindow* parent, int id, wxStri
m_panelControls->SetSizer( notebookSizer );
m_panelControls->Layout();
notebookSizer->Fit( m_panelControls );
+
dialogSizer->Add( m_panelControls, 1, wxALL|wxEXPAND, 1 );
m_panelButtons = new wxPanel( this, ID_DEFAULT, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
@@ -126,11 +127,12 @@ CDlgAdvPreferencesBase::CDlgAdvPreferencesBase( wxWindow* parent, int id, wxStri
dialogSizer->Fit( this );
this->SetSizer( dialogSizer );
- this->Layout();
}
wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
{
+ wxSize textCtrlSize = getTextCtrlSize(wxT("999.99"));
+
wxPanel* processorTab = new wxPanel( notebook, ID_TABPAGE_PROC, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
processorTab->SetExtraStyle( wxWS_EX_VALIDATE_RECURSIVELY );
@@ -180,8 +182,7 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
0, wxALL, 5
);
m_txtProcIdleFor = new wxTextCtrl(
- computingAllowedStaticBox, ID_TXTPROCIDLEFOR, wxT(""), wxDefaultPosition,
- wxSize( 50,-1 ), wxTE_RIGHT
+ computingAllowedStaticBox, ID_TXTPROCIDLEFOR, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("999.99")), wxTE_RIGHT
);
m_txtProcIdleFor->SetToolTip(
_("do work only after you haven't used the computer for this number of minutes")
@@ -214,8 +215,7 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
0, wxALL, 5
);
m_txtMaxLoad = new wxTextCtrl(
- computingAllowedStaticBox, ID_TXTMAXLOAD, wxT(""), wxDefaultPosition,
- wxSize( 50,-1 ), wxTE_RIGHT
+ computingAllowedStaticBox, ID_TXTMAXLOAD, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("100.00")), wxTE_RIGHT
);
m_txtMaxLoad->SetToolTip(
_("suspend work if processor usage exceeds this level")
@@ -240,7 +240,7 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
m_staticText351 = new wxStaticText( computingAllowedStaticBox, ID_DEFAULT, _("Every day between hours of"), wxDefaultPosition, wxDefaultSize, 0 );
cpuTimesSizer->Add( m_staticText351, 0, wxALL, 5 );
- m_txtProcEveryDayStart = new wxTextCtrl( computingAllowedStaticBox, ID_TXTPROCEVERYDAYSTART, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT );
+ m_txtProcEveryDayStart = new wxTextCtrl( computingAllowedStaticBox, ID_TXTPROCEVERYDAYSTART, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("23:59")), wxTE_RIGHT );
m_txtProcEveryDayStart->SetToolTip( _("start work at this time") );
cpuTimesSizer->Add( m_txtProcEveryDayStart, 0, wxALL, 1 );
@@ -248,7 +248,7 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
m_staticText25 = new wxStaticText( computingAllowedStaticBox, ID_DEFAULT, _("and"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE );
cpuTimesSizer->Add( m_staticText25, 0, wxALL|wxEXPAND, 5 );
- m_txtProcEveryDayStop = new wxTextCtrl( computingAllowedStaticBox, ID_TXTPROCEVERYDAYSTOP, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT );
+ m_txtProcEveryDayStop = new wxTextCtrl( computingAllowedStaticBox, ID_TXTPROCEVERYDAYSTOP, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("23:59")), wxTE_RIGHT );
m_txtProcEveryDayStop->SetToolTip( _("stop work at this time") );
cpuTimesSizer->Add( m_txtProcEveryDayStop, 0, wxALL, 1 );
@@ -273,49 +273,49 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
procDaysSizer->Add( m_chkProcMonday, 0, wxALL, 5 );
- m_txtProcMonday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCMONDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcMonday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCMONDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcMonday, 0, wxALL, 1 );
m_chkProcTuesday = new wxCheckBox( m_panelProcSpecialTimes, ID_CHKPROCTUESDAY, _("Tuesday"), wxDefaultPosition, wxDefaultSize, 0 );
procDaysSizer->Add( m_chkProcTuesday, 0, wxALL, 5 );
- m_txtProcTuesday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCTUESDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcTuesday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCTUESDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcTuesday, 0, wxALL, 1 );
m_chkProcWednesday = new wxCheckBox( m_panelProcSpecialTimes, ID_CHKPROCWEDNESDAY, _("Wednesday"), wxDefaultPosition, wxDefaultSize, 0 );
procDaysSizer->Add( m_chkProcWednesday, 0, wxALL, 5 );
- m_txtProcWednesday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCWEDNESDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcWednesday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCWEDNESDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcWednesday, 0, wxALL, 1 );
m_chkProcThursday = new wxCheckBox( m_panelProcSpecialTimes, ID_CHKPROCTHURSDAY, _("Thursday"), wxDefaultPosition, wxDefaultSize, 0 );
procDaysSizer->Add( m_chkProcThursday, 0, wxALL, 5 );
- m_txtProcThursday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCTHURSDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcThursday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCTHURSDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcThursday, 0, wxALL, 1 );
m_chkProcFriday = new wxCheckBox( m_panelProcSpecialTimes, ID_CHKPROCFRIDAY, _("Friday"), wxDefaultPosition, wxDefaultSize, 0 );
procDaysSizer->Add( m_chkProcFriday, 0, wxALL, 5 );
- m_txtProcFriday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCFRIDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcFriday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCFRIDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcFriday, 0, wxALL, 1 );
m_chkProcSaturday = new wxCheckBox( m_panelProcSpecialTimes, ID_CHKPROCSATURDAY, _("Saturday"), wxDefaultPosition, wxDefaultSize, 0 );
procDaysSizer->Add( m_chkProcSaturday, 0, wxALL, 5 );
- m_txtProcSaturday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCSATURDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcSaturday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCSATURDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcSaturday, 0, wxALL, 1 );
m_chkProcSunday = new wxCheckBox( m_panelProcSpecialTimes, ID_CHKPROCSUNDAY, _("Sunday"), wxDefaultPosition, wxDefaultSize, 0 );
procDaysSizer->Add( m_chkProcSunday, 0, wxALL, 5 );
- m_txtProcSunday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCSUNDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtProcSunday = new wxTextCtrl( m_panelProcSpecialTimes, ID_TXTPROCSUNDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
procDaysSizer->Add( m_txtProcSunday, 0, wxALL, 1 );
m_panelProcSpecialTimes->SetSizer( procDaysSizer );
@@ -335,8 +335,8 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
m_staticText18 = new wxStaticText( miscProcStaticBox, ID_DEFAULT, _("Switch between applications every"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
miscProcGridSizer->Add( m_staticText18, 0, wxALL|wxEXPAND, 5 );
-
- m_txtProcSwitchEvery = new wxTextCtrl( miscProcStaticBox, ID_TXTPROCSWITCHEVERY, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+
+ m_txtProcSwitchEvery = new wxTextCtrl( miscProcStaticBox, ID_TXTPROCSWITCHEVERY, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
miscProcGridSizer->Add( m_txtProcSwitchEvery, 0, wxALL, 1 );
m_staticText19 = new wxStaticText( miscProcStaticBox, ID_DEFAULT, _("minutes"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -345,7 +345,7 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
m_staticText20 = new wxStaticText( miscProcStaticBox, ID_DEFAULT, _("On multiprocessor systems, use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
miscProcGridSizer->Add( m_staticText20, 0, wxALL|wxEXPAND, 5 );
- m_txtProcUseProcessors = new wxTextCtrl( miscProcStaticBox, ID_TXTPROCUSEPROCESSORS, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtProcUseProcessors = new wxTextCtrl( miscProcStaticBox, ID_TXTPROCUSEPROCESSORS, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
miscProcGridSizer->Add( m_txtProcUseProcessors, 0, wxALL, 1 );
/*xgettext:no-c-format*/
@@ -355,7 +355,7 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
m_staticText22 = new wxStaticText( miscProcStaticBox, ID_DEFAULT, _("Use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
miscProcGridSizer->Add( m_staticText22, 0, wxALL|wxEXPAND, 5 );
- m_txtProcUseCPUTime = new wxTextCtrl( miscProcStaticBox, ID_TXTPOCUSECPUTIME, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtProcUseCPUTime = new wxTextCtrl( miscProcStaticBox, ID_TXTPOCUSECPUTIME, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
miscProcGridSizer->Add( m_txtProcUseCPUTime, 0, wxALL, 1 );
/*xgettext:no-c-format*/
@@ -376,6 +376,8 @@ wxPanel* CDlgAdvPreferencesBase::createProcessorTab(wxNotebook* notebook)
wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
{
+ wxSize textCtrlSize = getTextCtrlSize(wxT("9999.99"));
+
wxPanel* networkTab = new wxPanel( notebook, ID_TABPAGE_NET, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
networkTab->SetExtraStyle( wxWS_EX_VALIDATE_RECURSIVELY );
@@ -391,18 +393,18 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
// upload/download rates
m_staticText32 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("Maximum download rate"), wxDefaultPosition, wxDefaultSize, 0 );
- networkGeneralGridSizer->Add( m_staticText32, 0, wxALL, 5 );
+ networkGeneralGridSizer->Add( m_staticText32, 0, wxALIGN_RIGHT|wxALL, 5 );
- m_txtNetDownloadRate = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETDOWNLOADRATE, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT );
+ m_txtNetDownloadRate = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETDOWNLOADRATE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
networkGeneralGridSizer->Add( m_txtNetDownloadRate, 0, wxALL, 1 );
m_staticText33 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("KBytes/second (0 means no restriction)"), wxDefaultPosition, wxDefaultSize, 0 );
networkGeneralGridSizer->Add( m_staticText33, 0, wxALL, 5 );
-
+
m_staticText34 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("Maximum upload rate"), wxDefaultPosition, wxDefaultSize, 0 );
networkGeneralGridSizer->Add( m_staticText34, 0, wxALIGN_RIGHT|wxALL, 5 );
- m_txtNetUploadRate = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETUPLOADRATE, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT );
+ m_txtNetUploadRate = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETUPLOADRATE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
networkGeneralGridSizer->Add( m_txtNetUploadRate, 0, wxALL, 1 );
m_staticText35 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("KBytes/second (0 means no restriction)"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -414,11 +416,10 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
networkGeneralStaticBox, ID_DEFAULT,
_("Minimum work buffer"), wxDefaultPosition, wxDefaultSize, 0
);
- networkGeneralGridSizer->Add( m_staticText30, 0, wxALL, 5 );
+ networkGeneralGridSizer->Add( m_staticText30, 0, wxALIGN_RIGHT|wxALL, 5 );
m_txtNetConnectInterval = new wxTextCtrl(
- networkGeneralStaticBox, ID_TXTNETCONNECTINTERVAL, wxT(""),
- wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT
+ networkGeneralStaticBox, ID_TXTNETCONNECTINTERVAL, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT
);
m_txtNetConnectInterval->SetToolTip(
_("Try to maintain enough tasks to keep busy for this many days")
@@ -438,8 +439,7 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
networkGeneralGridSizer->Add( m_staticText331, 0, wxALIGN_RIGHT|wxALL, 5 );
m_txtNetAdditionalDays = new wxTextCtrl(
- networkGeneralStaticBox, ID_TXTNETADDITIONALDAYS, wxT(""),
- wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT
+ networkGeneralStaticBox, ID_TXTNETADDITIONALDAYS, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT
);
m_txtNetAdditionalDays->SetToolTip(
_("In addition, maintain enough tasks for up to this many days")
@@ -449,28 +449,29 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
m_staticText341 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("days (maximum value: 10)"), wxDefaultPosition, wxDefaultSize, 0 );
networkGeneralGridSizer->Add( m_staticText341, 0, wxALL, 5 );
- networkGeneralBoxSizer->Add( networkGeneralGridSizer, 0, wxEXPAND, 1 );
-
// long-term quota
- wxBoxSizer* networkTransferLimitSizer = new wxBoxSizer( wxHORIZONTAL );
-
m_staticText_daily_xfer1 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("Transfer at most"), wxDefaultPosition, wxDefaultSize, 0 );
- networkTransferLimitSizer->Add( m_staticText_daily_xfer1, 0, wxALL, 5 );
+ networkGeneralGridSizer->Add( m_staticText_daily_xfer1, 0, wxALIGN_RIGHT|wxALL, 5 );
+
+ m_txt_daily_xfer_limit_mb = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETDOWNLOADRATE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
+ networkGeneralGridSizer->Add( m_txt_daily_xfer_limit_mb, 0, wxALL, 1 );
- m_txt_daily_xfer_limit_mb = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETDOWNLOADRATE, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT );
- networkTransferLimitSizer->Add( m_txt_daily_xfer_limit_mb, 0, wxALL, 1 );
+ wxBoxSizer* networkTransferLimitSizer = new wxBoxSizer( wxHORIZONTAL );
m_staticText_daily_xfer2 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("MBytes every"), wxDefaultPosition, wxDefaultSize, 0 );
networkTransferLimitSizer->Add( m_staticText_daily_xfer2, 0, wxALL, 5 );
- m_txt_daily_xfer_period_days = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETUPLOADRATE, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), wxTE_RIGHT );
+ m_txt_daily_xfer_period_days = new wxTextCtrl( networkGeneralStaticBox, ID_TXTNETUPLOADRATE, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("999.99")), wxTE_RIGHT );
networkTransferLimitSizer->Add( m_txt_daily_xfer_period_days, 0, wxALL, 1 );
m_staticText_daily_xfer4 = new wxStaticText( networkGeneralStaticBox, ID_DEFAULT, _("days (0 means no restriction)"), wxDefaultPosition, wxDefaultSize, 0 );
networkTransferLimitSizer->Add( m_staticText_daily_xfer4, 0, wxALL, 5 );
- networkGeneralBoxSizer->Add( networkTransferLimitSizer, 0, wxALL, 0 );
+ networkGeneralGridSizer->Add( networkTransferLimitSizer, 0, wxALL, 0 );
+
+ networkGeneralBoxSizer->Add( networkGeneralGridSizer, 0, wxEXPAND, 1 );
+
m_chkNetSkipImageVerification = new wxCheckBox( networkGeneralStaticBox, ID_CHKNETSKIPIMAGEVERIFICATION, _("Skip image file verification"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -505,7 +506,7 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
m_staticText38 = new wxStaticText( networkTimesStaticBox, ID_DEFAULT, _("Every day between hours of"), wxDefaultPosition, wxDefaultSize, 0 );
networkTimesSizer->Add( m_staticText38, 0, wxALL, 5 );
- m_txtNetEveryDayStart = new wxTextCtrl( networkTimesStaticBox, ID_TXTNETEVERYDAYSTART, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), 0 );
+ m_txtNetEveryDayStart = new wxTextCtrl( networkTimesStaticBox, ID_TXTNETEVERYDAYSTART, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("23:59")), 0 );
m_txtNetEveryDayStart->SetToolTip( _("network usage start hour") );
networkTimesSizer->Add( m_txtNetEveryDayStart, 0, wxALL, 1 );
@@ -513,7 +514,7 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
m_staticText37 = new wxStaticText( networkTimesStaticBox, ID_DEFAULT, _("and"), wxDefaultPosition, wxDefaultSize, 0 );
networkTimesSizer->Add( m_staticText37, 0, wxALL, 5 );
- m_txtNetEveryDayStop = new wxTextCtrl( networkTimesStaticBox, ID_TXTNETEVERYDAYSTOP, wxT(""), wxDefaultPosition, wxSize( 50,-1 ), 0 );
+ m_txtNetEveryDayStop = new wxTextCtrl( networkTimesStaticBox, ID_TXTNETEVERYDAYSTOP, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("23:59")), 0 );
m_txtNetEveryDayStop->SetToolTip( _("network usage stop hour") );
networkTimesSizer->Add( m_txtNetEveryDayStop, 0, wxALL, 1 );
@@ -538,49 +539,49 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
netDaysGridSizer->Add( m_chkNetMonday, 0, wxALL, 5 );
- m_txtNetMonday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETMONDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetMonday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETMONDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetMonday, 0, wxALL, 1 );
m_chkNetTuesday = new wxCheckBox( m_panelNetSpecialTimes, ID_CHKNETTUESDAY, _("Tuesday"), wxDefaultPosition, wxDefaultSize, 0 );
netDaysGridSizer->Add( m_chkNetTuesday, 0, wxALL, 5 );
- m_txtNetTuesday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETTUESDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetTuesday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETTUESDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetTuesday, 0, wxALL, 1 );
m_chkNetWednesday = new wxCheckBox( m_panelNetSpecialTimes, ID_CHKNETWEDNESDAY, _("Wednesday"), wxDefaultPosition, wxDefaultSize, 0 );
netDaysGridSizer->Add( m_chkNetWednesday, 0, wxALL, 5 );
- m_txtNetWednesday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETWEDNESDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetWednesday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETWEDNESDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetWednesday, 0, wxALL, 1 );
m_chkNetThursday = new wxCheckBox( m_panelNetSpecialTimes, ID_CHKNETTHURSDAY, _("Thursday"), wxDefaultPosition, wxDefaultSize, 0 );
netDaysGridSizer->Add( m_chkNetThursday, 0, wxALL, 5 );
- m_txtNetThursday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETTHURSDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetThursday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETTHURSDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetThursday, 0, wxALL, 1 );
m_chkNetFriday = new wxCheckBox( m_panelNetSpecialTimes, ID_CHKNETFRIDAY, _("Friday"), wxDefaultPosition, wxDefaultSize, 0 );
netDaysGridSizer->Add( m_chkNetFriday, 0, wxALL, 5 );
- m_txtNetFriday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETFRIDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetFriday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETFRIDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetFriday, 0, wxALL, 1 );
m_chkNetSaturday = new wxCheckBox( m_panelNetSpecialTimes, ID_CHKNETSATURDAY, _("Saturday"), wxDefaultPosition, wxDefaultSize, 0 );
netDaysGridSizer->Add( m_chkNetSaturday, 0, wxALL, 5 );
- m_txtNetSaturday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETSATURDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetSaturday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETSATURDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetSaturday, 0, wxALL, 1 );
m_chkNetSunday = new wxCheckBox( m_panelNetSpecialTimes, ID_CHKNETSUNDAY, _("Sunday"), wxDefaultPosition, wxDefaultSize, 0 );
netDaysGridSizer->Add( m_chkNetSunday, 0, wxALL, 5 );
- m_txtNetSunday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETSUNDAY, wxT(""), wxDefaultPosition, wxDefaultSize, 0 );
+ m_txtNetSunday = new wxTextCtrl( m_panelNetSpecialTimes, ID_TXTNETSUNDAY, wxT(""), wxDefaultPosition, getTextCtrlSize(wxT("00:00-23:59")), 0 );
netDaysGridSizer->Add( m_txtNetSunday, 0, wxALL, 1 );
m_panelNetSpecialTimes->SetSizer( netDaysGridSizer );
@@ -599,6 +600,8 @@ wxPanel* CDlgAdvPreferencesBase::createNetworkTab(wxNotebook* notebook)
wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
{
+ wxSize textCtrlSize = getTextCtrlSize(wxT("9999.99"));
+
wxPanel* diskMemoryTab = new wxPanel( notebook, ID_TABPAGE_DISK, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
diskMemoryTab->SetExtraStyle( wxWS_EX_VALIDATE_RECURSIVELY );
@@ -615,7 +618,7 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText40 = new wxStaticText( diskUsageStaticBox, ID_DEFAULT, _("Use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
diskUsageGridSizer->Add( m_staticText40, 0, wxALL|wxEXPAND, 5 );
- m_txtDiskMaxSpace = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKMAXSPACE, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtDiskMaxSpace = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKMAXSPACE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
m_txtDiskMaxSpace->SetToolTip( _("the maximum disk space used by BOINC (in Gigabytes)") );
diskUsageGridSizer->Add( m_txtDiskMaxSpace, 0, wxALL, 1 );
@@ -626,7 +629,7 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText42 = new wxStaticText( diskUsageStaticBox, ID_DEFAULT, _("Leave at least"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
diskUsageGridSizer->Add( m_staticText42, 0, wxALL|wxEXPAND, 5 );
- m_txtDiskLeastFree = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKLEASTFREE, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtDiskLeastFree = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKLEASTFREE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
m_txtDiskLeastFree->SetToolTip( _("BOINC leaves at least this amount of disk space free (in Gigabytes)") );
diskUsageGridSizer->Add( m_txtDiskLeastFree, 0, wxALL, 1 );
@@ -637,7 +640,7 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText44 = new wxStaticText( diskUsageStaticBox, ID_DEFAULT, _("Use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
diskUsageGridSizer->Add( m_staticText44, 0, wxALL|wxEXPAND, 5 );
- m_txtDiskMaxOfTotal = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKMAXOFTOTAL, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtDiskMaxOfTotal = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKMAXOFTOTAL, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
m_txtDiskMaxOfTotal->SetToolTip( _("BOINC uses at most this percentage of total disk space") );
diskUsageGridSizer->Add( m_txtDiskMaxOfTotal, 0, wxALL, 1 );
@@ -649,7 +652,7 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText46 = new wxStaticText( diskUsageStaticBox, ID_DEFAULT, _("Tasks checkpoint to disk at most every"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
diskUsageGridSizer->Add( m_staticText46, 0, wxALL|wxEXPAND, 5 );
- m_txtDiskWriteToDisk = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKWRITETODISK, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtDiskWriteToDisk = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKWRITETODISK, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
diskUsageGridSizer->Add( m_txtDiskWriteToDisk, 0, wxALL, 1 );
m_staticText47 = new wxStaticText( diskUsageStaticBox, ID_DEFAULT, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -658,7 +661,7 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText48 = new wxStaticText( diskUsageStaticBox, ID_DEFAULT, _("Use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
diskUsageGridSizer->Add( m_staticText48, 0, wxALL|wxEXPAND, 5 );
- m_txtDiskMaxSwap = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKWRITETODISK, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtDiskMaxSwap = new wxTextCtrl( diskUsageStaticBox, ID_TXTDISKWRITETODISK, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
diskUsageGridSizer->Add( m_txtDiskMaxSwap, 0, wxALL, 1 );
/*xgettext:no-c-format*/
@@ -680,7 +683,8 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText50 = new wxStaticText( memoryUsageStaticBox, ID_DEFAULT, _("Use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
memoryUsageGridSizer->Add( m_staticText50, 0, wxALL|wxEXPAND, 5 );
- m_txtMemoryMaxInUse = new wxTextCtrl( memoryUsageStaticBox, ID_TXTMEMORYMAXINUSE, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ textCtrlSize = getTextCtrlSize(wxT("100.00"));
+ m_txtMemoryMaxInUse = new wxTextCtrl( memoryUsageStaticBox, ID_TXTMEMORYMAXINUSE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
memoryUsageGridSizer->Add( m_txtMemoryMaxInUse, 0, wxALL, 1 );
/*xgettext:no-c-format*/
@@ -690,7 +694,7 @@ wxPanel* CDlgAdvPreferencesBase::createDiskAndMemoryTab(wxNotebook* notebook)
m_staticText52 = new wxStaticText( memoryUsageStaticBox, ID_DEFAULT, _("Use at most"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
memoryUsageGridSizer->Add( m_staticText52, 0, wxALL|wxEXPAND, 5 );
- m_txtMemoryMaxOnIdle = new wxTextCtrl( memoryUsageStaticBox, ID_TXTMEMORYMAXONIDLE, wxT(""), wxDefaultPosition, wxSize( 75,-1 ), wxTE_RIGHT );
+ m_txtMemoryMaxOnIdle = new wxTextCtrl( memoryUsageStaticBox, ID_TXTMEMORYMAXONIDLE, wxT(""), wxDefaultPosition, textCtrlSize, wxTE_RIGHT );
memoryUsageGridSizer->Add( m_txtMemoryMaxOnIdle, 0, wxALL, 1 );
/*xgettext:no-c-format*/
@@ -779,3 +783,16 @@ wxPanel* CDlgAdvPreferencesBase::createExclusiveAppsTab(wxNotebook* notebook)
return exclusiveAppsTab;
}
+
+wxSize CDlgAdvPreferencesBase::getTextCtrlSize(wxString maxText) {
+ int w, h, margin;
+ wxSize sz;
+ wxFont f = GetParent()->GetFont();
+ GetTextExtent(maxText, &w, &h, NULL, NULL, &f);
+ margin = w/3;
+ if (margin < 9) margin = 9;
+ sz.x = w + margin;
+ sz.y = wxDefaultCoord;
+ return sz;
+}
+
diff --git a/clientgui/DlgAdvPreferencesBase.h b/clientgui/DlgAdvPreferencesBase.h
index 0fa81ef..0d03c3e 100644
--- a/clientgui/DlgAdvPreferencesBase.h
+++ b/clientgui/DlgAdvPreferencesBase.h
@@ -235,13 +235,14 @@ protected:
wxButton* m_btnHelp;
public:
- CDlgAdvPreferencesBase( wxWindow* parent, int id = -1, wxString title = wxT(""), wxPoint pos = wxDefaultPosition, wxSize size = wxSize( 547,526 ), int style = wxDEFAULT_DIALOG_STYLE );
+ CDlgAdvPreferencesBase( wxWindow* parent, int id = -1, wxString title = wxT(""), wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize, int style = wxDEFAULT_DIALOG_STYLE );
private:
wxPanel* createProcessorTab(wxNotebook* notebook);
wxPanel* createNetworkTab(wxNotebook* notebook);
wxPanel* createDiskAndMemoryTab(wxNotebook* notebook);
wxPanel* createExclusiveAppsTab(wxNotebook* notebook);
+ wxSize getTextCtrlSize(wxString maxText);
};
#endif //__DlgAdvPreferencesBase__
diff --git a/clientgui/MainDocument.cpp b/clientgui/MainDocument.cpp
index 5535a95..2f8dd65 100644
--- a/clientgui/MainDocument.cpp
+++ b/clientgui/MainDocument.cpp
@@ -2601,3 +2601,37 @@ wxString result_description(RESULT* result, bool show_resources) {
return strBuffer;
}
+static void hsv2rgb(
+ double h, double s, double v, double& r, double& g, double& b
+) {
+ double m, n, f;
+ int i = floor(h);
+ f = h - i;
+ if (!(i&1)) f = 1 - f;
+ m = v * (1 - s);
+ n = v * (1 - s*f);
+ switch (i) {
+ case 6:
+ case 0: r = v; g = n; b = m; return;
+ case 1: r = n; g = v; b = m; return;
+ case 2: r = m; g = v; b = n; return;
+ case 3: r = m; g = n; b = v; return;
+ case 4: r = n; g = m; b = v; return;
+ case 5: r = v; g = m; b = n; return;
+ }
+}
+
+// return the ith out of n maximally distinct colors
+//
+void color_cycle(int i, int n, wxColour& color) {
+ double h = (double)i/(double)n;
+ double r, g, b;
+ double v = .6;
+ if (n > 6) v = .5 + (i % 3)*.125;
+ // cycle through 3 different brightnesses
+ hsv2rgb(h*6, .5, v, r, g, b);
+ unsigned char cr = (unsigned char) (r*256);
+ unsigned char cg = (unsigned char) (g*256);
+ unsigned char cb = (unsigned char) (b*256);
+ color = wxColour(cr, cg, cb);
+}
diff --git a/clientgui/MainDocument.h b/clientgui/MainDocument.h
index 11d1d5c..0348f45 100644
--- a/clientgui/MainDocument.h
+++ b/clientgui/MainDocument.h
@@ -415,6 +415,7 @@ extern void localize(wxString& strMessage);
extern void eol_to_br(wxString& strMessage);
extern void remove_eols(wxString& strMessage);
extern void https_to_http(wxString& strMessage);
+extern void color_cycle(int i, int n, wxColour& color);
#ifdef SANDBOX
#define BOINC_MASTER_GROUP_NAME "boinc_master"
diff --git a/clientgui/ViewResources.cpp b/clientgui/ViewResources.cpp
index 5d8d555..72e8022 100644
--- a/clientgui/ViewResources.cpp
+++ b/clientgui/ViewResources.cpp
@@ -165,24 +165,6 @@ bool CViewResources::OnRestoreState(wxConfigBase* /*pConfig*/) {
return true;
}
-void hsv2rgb(double h, double s, double v, double& r, double& g, double& b) {
- double m, n, f;
- int i = floor(h);
- f = h - i;
- if (!(i&1)) f = 1 - f;
- m = v * (1 - s);
- n = v * (1 - s*f);
- switch (i) {
- case 6:
- case 0: r = v; g = n; b = m; return;
- case 1: r = n; g = v; b = m; return;
- case 2: r = m; g = v; b = n; return;
- case 3: r = m; g = n; b = v; return;
- case 4: r = n; g = m; b = v; return;
- case 5: r = v; g = m; b = n; return;
- }
-}
-
void CViewResources::OnListRender( wxTimerEvent& WXUNUSED(event) ) {
CMainDocument* pDoc = wxGetApp().GetDocument();
wxString diskspace;
@@ -228,15 +210,9 @@ void CViewResources::OnListRender( wxTimerEvent& WXUNUSED(event) ) {
wxPiePart part;
part.SetLabel(projectname + wxT(": ") + diskspace);
part.SetValue(usage);
- double h = (double)i/(double)pDoc->disk_usage.projects.size();
- double r, g, b;
- double v = .5 + (i % 3)*.2;
- // cycle through 3 different brightnesses
- hsv2rgb(h*6, .5, v, r, g, b);
- unsigned char cr = (unsigned char) (r*256);
- unsigned char cg = (unsigned char) (g*256);
- unsigned char cb = (unsigned char) (b*256);
- part.SetColour(wxColour(cr, cg, cb));
+ wxColour color;
+ color_cycle(i, pDoc->disk_usage.projects.size(), color);
+ part.SetColour(color);
m_pieCtrlBOINC->m_Series.Add(part);
}
m_pieCtrlBOINC->Refresh();
diff --git a/clientgui/ViewStatistics.cpp b/clientgui/ViewStatistics.cpp
index 04b2aa2..00fef81 100644
--- a/clientgui/ViewStatistics.cpp
+++ b/clientgui/ViewStatistics.cpp
@@ -36,7 +36,8 @@ enum { // Command buttons (m_SelectedStatistic)
show_user_total = 0,
show_user_average,
show_host_total,
- show_host_average
+ show_host_average,
+ n_command_buttons
};
enum { // Mode buttons (m_ModeViewStatistic)
@@ -184,17 +185,6 @@ CPaintStatistics::CPaintStatistics(wxWindow* parent, wxWindowID id, const wxPoin
m_pen_GraphRACColour = wxColour(0, 160, 0);
m_pen_GraphTotalHostColour = wxColour(0, 0, 255);
m_pen_GraphRACHostColour = wxColour(0, 0, 0);
-
- m_pen_GraphColour00 = wxColour(255, 0, 0);
- m_pen_GraphColour01 = wxColour(0, 160, 0);
- m_pen_GraphColour02 = wxColour(0, 0, 255);
- m_pen_GraphColour03 = wxColour(0, 0, 0);
- m_pen_GraphColour04 = wxColour(255, 0, 255);
- m_pen_GraphColour05 = wxColour(255, 128, 0);
- m_pen_GraphColour06 = wxColour(192, 192, 0);
- m_pen_GraphColour07 = wxColour(0, 192, 192);
- m_pen_GraphColour08 = wxColour(160, 160, 160);
- m_pen_GraphColour09 = wxColour(160, 0, 0);
m_dc_bmp.Create(1, 1);
m_full_repaint = true;
@@ -239,20 +229,6 @@ static bool CrossTwoLine(const double X1_1, const double Y1_1, const double X1_2
}
}
-void CPaintStatistics::getDrawColour(wxColour &graphColour, int number) {
- switch (number % 10){
- case 1: graphColour = m_pen_GraphColour01; break;
- case 2: graphColour = m_pen_GraphColour02; break;
- case 3: graphColour = m_pen_GraphColour03; break;
- case 4: graphColour = m_pen_GraphColour04; break;
- case 5: graphColour = m_pen_GraphColour05; break;
- case 6: graphColour = m_pen_GraphColour06; break;
- case 7: graphColour = m_pen_GraphColour07; break;
- case 8: graphColour = m_pen_GraphColour08; break;
- case 9: graphColour = m_pen_GraphColour09; break;
- default:graphColour = m_pen_GraphColour00;
- }
-}
//----Draw "Point"
static void myDrawPoint(wxDC &dc,int X, int Y, wxColour graphColour,int numberTypePoint, int PointWidth) {
dc.SetPen(wxPen(graphColour , 1 , wxSOLID));
@@ -632,7 +608,7 @@ void CPaintStatistics::DrawLegend(wxDC &dc, PROJECTS* proj, CMainDocument* pDoc,
int typePoint = 0;
if (bColour){
getTypePoint(typePoint, count);
- getDrawColour(graphColour, count);
+ color_cycle(count, proj->projects.size(), graphColour);
} else if (SelProj == count) {
graphColour = m_pen_LegendSelectTextColour;
} else {
@@ -1317,7 +1293,7 @@ void CPaintStatistics::DrawAll(wxDC &dc) {
DrawAxis(dc, max_val_y, min_val_y,max_val_x, min_val_x, m_pen_AxisColour, max_val_y_all, min_val_y_all);
//Draw graph
wxColour graphColour=wxColour(0,0,0);
- getDrawColour(graphColour,m_SelectedStatistic);
+ color_cycle(m_SelectedStatistic, n_command_buttons, graphColour);
DrawGraph(dc, i, graphColour, 0, m_SelectedStatistic);
//Change row/col
if (col == nb_proj_col) {
@@ -1384,7 +1360,7 @@ void CPaintStatistics::DrawAll(wxDC &dc) {
DrawAxis(dc, max_val_y, min_val_y, max_val_x, min_val_x, pen_AxisColour1, max_val_y, min_val_y);
// Draw graph
wxColour graphColour=wxColour(0,0,0);
- getDrawColour(graphColour,m_SelectedStatistic);
+ color_cycle(m_SelectedStatistic, n_command_buttons, graphColour);
DrawGraph(dc, i, graphColour, 0, m_SelectedStatistic);
// Draw marker
DrawMarker(dc);
@@ -1454,7 +1430,7 @@ void CPaintStatistics::DrawAll(wxDC &dc) {
wxColour graphColour = wxColour(0,0,0);
int typePoint = 0;
getTypePoint(typePoint,count);
- getDrawColour(graphColour,count);
+ color_cycle(count, proj->projects.size(), graphColour);
DrawGraph(dc, i, graphColour, typePoint, m_SelectedStatistic);
}
}
@@ -1591,7 +1567,7 @@ void CPaintStatistics::DrawAll(wxDC &dc) {
wxColour graphColour = wxColour(0,0,0);
int typePoint = 0;
getTypePoint(typePoint,count);
- getDrawColour(graphColour,m_SelectedStatistic);
+ color_cycle(m_SelectedStatistic, n_command_buttons, graphColour);
DrawGraph2(dc, sumstats, graphColour, typePoint, m_SelectedStatistic);
// sumstats.clear();
//Draw marker
diff --git a/clientgui/ViewStatistics.h b/clientgui/ViewStatistics.h
index c88a954..274f8e8 100644
--- a/clientgui/ViewStatistics.h
+++ b/clientgui/ViewStatistics.h
@@ -47,8 +47,6 @@ public:
void DrawMarker(wxDC &dc);
- void getDrawColour(wxColour &graphColour, int number);
-
void ClearXY();
void ClearLegendXY();
@@ -185,16 +183,6 @@ public:
wxColour m_pen_GraphTotalHostColour;
wxColour m_pen_GraphRACHostColour;
- wxColour m_pen_GraphColour00;
- wxColour m_pen_GraphColour01;
- wxColour m_pen_GraphColour02;
- wxColour m_pen_GraphColour03;
- wxColour m_pen_GraphColour04;
- wxColour m_pen_GraphColour05;
- wxColour m_pen_GraphColour06;
- wxColour m_pen_GraphColour07;
- wxColour m_pen_GraphColour08;
- wxColour m_pen_GraphColour09;
protected:
void OnPaint(wxPaintEvent& event);
void OnEraseBackground(wxEraseEvent & /*event*/){};
diff --git a/configure.ac b/configure.ac
index 44dcd1e..57543f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@ dnl not sure exactly what the minimum version is (but 2.13 wont work)
AC_PREREQ(2.58)
dnl Set the BOINC version here. You can also use the set-version script.
-AC_INIT(BOINC, 7.4.8)
+AC_INIT(BOINC, 7.4.14)
AC_CONFIG_MACRO_DIR([m4])
LIBBOINC_VERSION=`echo ${PACKAGE_VERSION} | sed 's/\./:/g'`
AC_SUBST([LIBBOINC_VERSION])
diff --git a/db/boinc_db_types.h b/db/boinc_db_types.h
index 1580ac3..26179c8 100644
--- a/db/boinc_db_types.h
+++ b/db/boinc_db_types.h
@@ -201,6 +201,9 @@ struct USER {
// is being verified.
bool has_profile;
char cross_project_id[256];
+ // the "internal" cross-project ID;
+ // the "external CPID" that gets exported to stats sites
+ // is MD5(cpid, email)
char passwd_hash[256];
bool email_validated; // deprecated
int donated;
@@ -347,6 +350,8 @@ struct HOST {
//
char p_features[1024];
char virtualbox_version[256];
+ char client_brand[256];
+ // as specific in client_brand.txt config file on client
bool p_vm_extensions_disabled;
int num_opencl_cpu_platforms;
OPENCL_CPU_PROP opencl_cpu_prop[MAX_OPENCL_CPU_PLATFORMS];
diff --git a/lib/coproc.cpp b/lib/coproc.cpp
index 42bfd8e..9f581f0 100644
--- a/lib/coproc.cpp
+++ b/lib/coproc.cpp
@@ -102,14 +102,23 @@ void PCI_INFO::write(MIOFILE& f) {
);
}
-void COPROC::write_xml(MIOFILE& f) {
+void COPROC::write_xml(MIOFILE& f, bool scheduler_rpc) {
f.printf(
"<coproc>\n"
" <type>%s</type>\n"
- " <count>%d</count>\n"
- "</coproc>\n",
+ " <count>%d</count>\n",
type, count
);
+
+ if (scheduler_rpc) {
+ write_request(f);
+ }
+
+ if (have_opencl) {
+ opencl_prop.write_xml(f, "coproc_opencl");
+ }
+
+ f.printf("</coproc>\n");
}
void COPROC::write_request(MIOFILE& f) {
@@ -232,17 +241,24 @@ int COPROCS::parse(XML_PARSER& xp) {
void COPROCS::write_xml(MIOFILE& mf, bool scheduler_rpc) {
#ifndef _USING_FCGI_
-//TODO: Write coprocs[0] through coprocs[n_rsc]
mf.printf(" <coprocs>\n");
- if (nvidia.count) {
- nvidia.write_xml(mf, scheduler_rpc);
- }
- if (ati.count) {
- ati.write_xml(mf, scheduler_rpc);
- }
- if (intel_gpu.count) {
- intel_gpu.write_xml(mf, scheduler_rpc);
+
+ for (int i=1; i<n_rsc; i++) {
+ switch (coproc_type_name_to_num(coprocs[i].type)) {
+ case PROC_TYPE_NVIDIA_GPU:
+ nvidia.write_xml(mf, scheduler_rpc);
+ break;
+ case PROC_TYPE_AMD_GPU:
+ ati.write_xml(mf, scheduler_rpc);
+ break;
+ case PROC_TYPE_INTEL_GPU:
+ intel_gpu.write_xml(mf, scheduler_rpc);
+ break;
+ default:
+ coprocs[i].write_xml(mf, scheduler_rpc);
+ }
}
+
mf.printf(" </coprocs>\n");
#endif
}
@@ -883,7 +899,7 @@ void COPROC_INTEL::fake(double ram, double avail_ram, int n) {
// <coproc>
// <type>xxx</type>
//
-// Don't confused this with the element names used for GPUS within <coprocs>,
+// Don't confuse this with the element names used for GPUS within <coprocs>,
// namely:
// coproc_cuda
// coproc_ati
@@ -914,5 +930,5 @@ int coproc_type_name_to_num(const char* name) {
if (!strcmp(name, "NVIDIA")) return PROC_TYPE_NVIDIA_GPU;
if (!strcmp(name, "ATI")) return PROC_TYPE_AMD_GPU;
if (!strcmp(name, "intel_gpu")) return PROC_TYPE_INTEL_GPU;
- return 0;
+ return -1; // Some other type
}
diff --git a/lib/coproc.h b/lib/coproc.h
index 792b99f..2d699df 100644
--- a/lib/coproc.h
+++ b/lib/coproc.h
@@ -57,6 +57,15 @@
// that are incapable of handling them, and it involves no server changes.
// Its drawback is that, on systems with multiple and differing GPUs,
// it may not use some GPUs that actually could be used.
+//
+// Modified (as of 23 July 14) to allow coprocessors (OpenCL GPUs and OpenCL
+// accelerators) from vendors other than original 3: NVIDIA, AMD and Intel.
+// For these original 3 GPU vendors, we still use the above approach, and the
+// COPROC::type field contains a standardized vendor name "NVIDIA", "ATI" or
+// "intel_gpu". But for other, "new" vendors, we treat each device as a
+// separate resource, creating an entry for each instance in the
+// COPROCS::coprocs[] array and copying the device name COPROC::opencl_prop.name
+// into the COPROC::type field (instead of the vendor name.)
#ifndef _COPROC_
#define _COPROC_
@@ -88,11 +97,23 @@
// arguments to proc_type_name() and proc_type_name_xml().
//
-#define PROC_TYPE_CPU 0
-#define PROC_TYPE_NVIDIA_GPU 1
-#define PROC_TYPE_AMD_GPU 2
-#define PROC_TYPE_INTEL_GPU 3
-#define NPROC_TYPES 4
+enum {
+ PROC_TYPE_CPU=0,
+ PROC_TYPE_NVIDIA_GPU,
+ PROC_TYPE_AMD_GPU,
+ PROC_TYPE_INTEL_GPU,
+ PROC_TYPE_A,
+ PROC_TYPE_B,
+ PROC_TYPE_C,
+ PROC_TYPE_D,
+ PROC_TYPE_E,
+ PROC_TYPE_F,
+ PROC_TYPE_G,
+ NPROC_TYPES
+};
+
+extern const char* proc_type_names_xml[NPROC_TYPES];
+extern const char* proc_type_names[NPROC_TYPES];
extern const char* proc_type_name(int);
// user-readable name
@@ -104,6 +125,13 @@ extern int coproc_type_name_to_num(const char* name);
#define GPU_TYPE_NVIDIA proc_type_name_xml(PROC_TYPE_NVIDIA_GPU)
#define GPU_TYPE_ATI proc_type_name_xml(PROC_TYPE_AMD_GPU)
#define GPU_TYPE_INTEL proc_type_name_xml(PROC_TYPE_INTEL_GPU)
+#define COPROC_TYPE_A proc_type_name_xml(PROC_TYPE_A)
+#define COPROC_TYPE_B proc_type_name_xml(PROC_TYPE_B)
+#define COPROC_TYPE_C proc_type_name_xml(PROC_TYPE_C)
+#define COPROC_TYPE_D proc_type_name_xml(PROC_TYPE_D)
+#define COPROC_TYPE_E proc_type_name_xml(PROC_TYPE_E)
+#define COPROC_TYPE_F proc_type_name_xml(PROC_TYPE_F)
+#define COPROC_TYPE_G proc_type_name_xml(PROC_TYPE_G)
// represents a requirement for a coproc.
// This is a parsed version of the <coproc> elements in an <app_version>
@@ -184,7 +212,7 @@ struct COPROC {
OPENCL_DEVICE_PROP opencl_prop;
#ifndef _USING_FCGI_
- void write_xml(MIOFILE&);
+ void write_xml(MIOFILE&, bool scheduler_rpc=false);
void write_request(MIOFILE&);
#endif
int parse(XML_PARSER&);
@@ -399,6 +427,7 @@ struct COPROCS {
void set_path_to_client(char *path);
int write_coproc_info_file(std::vector<std::string> &warnings);
int read_coproc_info_file(std::vector<std::string> &warnings);
+ int add_other_coproc_types();
#ifdef __APPLE__
void opencl_get_ati_mem_size_from_opengl(std::vector<std::string> &warnings);
diff --git a/lib/error_numbers.h b/lib/error_numbers.h
index 2de17d1..fc7d14e 100644
--- a/lib/error_numbers.h
+++ b/lib/error_numbers.h
@@ -202,6 +202,7 @@
#define ERR_ABORTED_ON_EXIT -232
#define ERR_PROC_PARSE -235
#define ERR_STATFS -236
+#define ERR_PIPE -237
// PLEASE: add a text description of your error to
// the text description function boincerror() in str_util.cpp.
diff --git a/lib/gui_rpc_client.h b/lib/gui_rpc_client.h
index 65a70ce..757aab4 100644
--- a/lib/gui_rpc_client.h
+++ b/lib/gui_rpc_client.h
@@ -170,6 +170,7 @@ struct PROJECT {
char venue[256];
int njobs_success;
int njobs_error;
+ char external_cpid[64];
// NOTE: if you add any data items above,
// update parse(), and clear() to include them!!
diff --git a/lib/gui_rpc_client_ops.cpp b/lib/gui_rpc_client_ops.cpp
index ec45bed..2a90055 100644
--- a/lib/gui_rpc_client_ops.cpp
+++ b/lib/gui_rpc_client_ops.cpp
@@ -459,6 +459,7 @@ int PROJECT::parse(XML_PARSER& xp) {
if (xp.parse_str("venue", venue, sizeof(venue))) continue;
if (xp.parse_int("njobs_success", njobs_success)) continue;
if (xp.parse_int("njobs_error", njobs_error)) continue;
+ if (xp.parse_str("external_cpid", external_cpid, sizeof(external_cpid))) continue;
}
return ERR_XML_PARSE;
}
@@ -512,6 +513,7 @@ void PROJECT::clear() {
strcpy(venue, "");
njobs_success = 0;
njobs_error = 0;
+ strcpy(external_cpid, "");
}
APP::APP() {
diff --git a/lib/gui_rpc_client_print.cpp b/lib/gui_rpc_client_print.cpp
index b2472a8..4f576c1 100644
--- a/lib/gui_rpc_client_print.cpp
+++ b/lib/gui_rpc_client_print.cpp
@@ -108,6 +108,7 @@ void PROJECT::print() {
}
printf(" jobs succeeded: %d\n", njobs_success);
printf(" jobs failed: %d\n", njobs_error);
+ printf(" cross-project ID: %s\n", external_cpid);
}
void APP::print() {
diff --git a/lib/opencl_boinc.h b/lib/opencl_boinc.h
index e2ac403..7e16aa6 100644
--- a/lib/opencl_boinc.h
+++ b/lib/opencl_boinc.h
@@ -38,7 +38,7 @@ struct OPENCL_DEVICE_PROP {
cl_device_id device_id;
char name[256]; // Device name
char vendor[256]; // Device vendor (NVIDIA, ATI, AMD, etc.)
- cl_uint vendor_id; // OpenCL ID of device vendor
+ cl_uint vendor_id; // Vendor's unique ID for this device on this host
cl_bool available; // Is this device available?
cl_device_fp_config half_fp_config; // Half precision capabilities
cl_device_fp_config single_fp_config; // Single precision
@@ -63,7 +63,7 @@ struct OPENCL_DEVICE_PROP {
double peak_flops; // temp used in scan process
COPROC_USAGE is_used; // temp used in scan process
double opencl_available_ram; // temp used in scan process
- int opencl_device_index; // temp used in scan process
+ int opencl_device_index; // zero-based device number within this COPROC type
void write_xml(MIOFILE&, const char* tag, bool temp_file=false);
int parse(XML_PARSER&, const char* end_tag);
diff --git a/lib/proc_control.cpp b/lib/proc_control.cpp
index 8ef8775..0eeacb6 100644
--- a/lib/proc_control.cpp
+++ b/lib/proc_control.cpp
@@ -49,6 +49,10 @@ using std::vector;
//#define DEBUG
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
static void get_descendants_aux(PROC_MAP& pm, int pid, vector<int>& pids) {
PROC_MAP::iterator i = pm.find(pid);
if (i == pm.end()) return;
diff --git a/lib/procinfo_mac.cpp b/lib/procinfo_mac.cpp
index 705c534..639a463 100644
--- a/lib/procinfo_mac.cpp
+++ b/lib/procinfo_mac.cpp
@@ -101,8 +101,11 @@ int procinfo_setup(PROC_MAP& pm) {
// This eliminates the need to install our own application which runs setuid
// root; this was perceived by some users as a security risk.
-
- fd = popen("ps -axcopid,ppid,rss,vsz,pagein,pri,time,command", "r");
+// Under OS 10.8.x (only) ps writes a spurious warning to stderr if called
+// from a process that has the DYLD_LIBRARY_PATH environment variable set.
+// "env -i command" prevents the command from inheriting the caller's
+// environment, which avoids the spurious warning.
+ fd = popen("env -i ps -axcopid,ppid,rss,vsz,pagein,pri,time,command", "r");
if (!fd) return ERR_FOPEN;
// Skip over the header line
diff --git a/lib/shmem.cpp b/lib/shmem.cpp
index 8d90468..00b3cb7 100644
--- a/lib/shmem.cpp
+++ b/lib/shmem.cpp
@@ -418,7 +418,7 @@ int create_shmem(key_t key, int size, gid_t gid, void** pp) {
}
if (id < 0) {
perror("shmget");
- fprintf(stderr,"shmem size: %d\n", size);
+ fprintf(stderr, "shmem size: %d\n", size);
return ERR_SHMGET;
}
diff --git a/lib/str_util.cpp b/lib/str_util.cpp
index a573620..041a57b 100644
--- a/lib/str_util.cpp
+++ b/lib/str_util.cpp
@@ -527,6 +527,7 @@ const char* boincerror(int which_error) {
case ERR_CRYPTO: return "encryption error";
case ERR_ABORTED_ON_EXIT: return "job was aborted on client exit";
case ERR_PROC_PARSE: return "a /proc entry was not parsed correctly";
+ case ERR_PIPE: return "pipe() failed";
case 404: return "HTTP file not found";
case 407: return "HTTP proxy authentication failure";
case 416: return "HTTP range request error";
diff --git a/lib/util.cpp b/lib/util.cpp
index d44fea5..5ec56a3 100644
--- a/lib/util.cpp
+++ b/lib/util.cpp
@@ -461,10 +461,35 @@ int run_program(
#endif
#ifdef _WIN32
+int kill_program(int pid, int exit_code) {
+ int retval;
+
+ HANDLE h = OpenProcess(PROCESS_TERMINATE, false, pid);
+ if (h == NULL && GetLastError() == ERROR_ACCESS_DENIED) return EPERM;
+ if (h == NULL && GetLastError() == ERROR_INVALID_PARAMETER) return EINVAL;
+ if (h == NULL && GetLastError() == ERROR_FILE_NOT_FOUND) return ESRCH;
+ if (h == NULL) return EIO;
+ if (TerminateProcess(h, exit_code)) {
+ retval = 0;
+ } else {
+ retval = 1;
+ }
+ CloseHandle(h);
+
+ return retval;
+}
void kill_program(HANDLE pid) {
TerminateProcess(pid, 0);
}
#else
+int kill_program(int pid, int exit_code) {
+ int retval;
+ retval = kill(pid, SIGKILL);
+ if (-1 == retval) {
+ retval = errno;
+ }
+ return retval;
+}
void kill_program(int pid) {
kill(pid, SIGKILL);
}
diff --git a/lib/util.h b/lib/util.h
index 3b89817..0db7588 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -91,6 +91,7 @@ extern int run_program(
);
extern void kill_program(HANDLE);
+extern int kill_program(int, int);
extern int get_exit_status(HANDLE);
extern bool process_exists(HANDLE);
@@ -100,6 +101,7 @@ extern int run_program(
const char* dir, const char* file, int argc, char *const argv[], double, int&
);
extern void kill_program(int);
+extern int kill_program(int, int);
extern int get_exit_status(int);
extern bool process_exists(int);
#endif
diff --git a/sched/handle_request.cpp b/sched/handle_request.cpp
index e886f70..8a1f93b 100644
--- a/sched/handle_request.cpp
+++ b/sched/handle_request.cpp
@@ -500,11 +500,16 @@ static int modify_host_struct(HOST& host) {
host.timezone = g_request->host.timezone;
strncpy(host.domain_name, g_request->host.domain_name, sizeof(host.domain_name));
char buf[1024], buf2[1024];
- sprintf(buf, "[BOINC|%d.%d.%d]",
+ sprintf(buf, "[BOINC|%d.%d.%d",
g_request->core_client_major_version,
g_request->core_client_minor_version,
g_request->core_client_release
);
+ if (strlen(host.client_brand)) {
+ strcat(buf, "|");
+ strcat(buf, host.client_brand);
+ }
+ strcat(buf, "]");
g_request->coprocs.summary_string(buf2, sizeof(buf2));
strlcpy(host.serialnum, buf, sizeof(host.serialnum));
strlcat(host.serialnum, buf2, sizeof(host.serialnum));
diff --git a/sched/sched_types.cpp b/sched/sched_types.cpp
index decdc94..2a8e64a 100644
--- a/sched/sched_types.cpp
+++ b/sched/sched_types.cpp
@@ -772,9 +772,15 @@ int SCHEDULER_REPLY::write(FILE* fout, SCHEDULER_REQUEST& sreq) {
);
}
if (strlen(user.cross_project_id)) {
+ char external_cpid[MD5_LEN];
+ safe_strcpy(buf, user.cross_project_id);
+ safe_strcat(buf, user.email_addr);
+ md5_block((unsigned char*)buf, strlen(buf), external_cpid);
fprintf(fout,
- "<cross_project_id>%s</cross_project_id>\n",
- user.cross_project_id
+ "<cross_project_id>%s</cross_project_id>\n"
+ "<external_cpid>%s</external_cpid>\n",
+ user.cross_project_id,
+ external_cpid
);
}
@@ -1247,6 +1253,7 @@ int HOST::parse(XML_PARSER& xp) {
if (xp.parse_double("n_bwdown", n_bwdown)) continue;
if (xp.parse_str("p_features", p_features, sizeof(p_features))) continue;
if (xp.parse_str("virtualbox_version", virtualbox_version, sizeof(virtualbox_version))) continue;
+ if (xp.parse_str("client_brand", client_brand, sizeof(client_brand))) continue;
if (xp.parse_bool("p_vm_extensions_disabled", p_vm_extensions_disabled)) continue;
if (xp.match_tag("opencl_cpu_prop")) {
int retval = opencl_cpu_prop[num_opencl_cpu_platforms].parse(xp);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-boinc/boinc.git
More information about the pkg-boinc-commits
mailing list